Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release Version 2.3.0 #44

Merged
merged 11 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/build-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Build and Push Multi-Arch Images

on:
push:
branches:
- develop
- main
tags:
- "v*.*.*"

jobs:
get-tag:
runs-on: ubuntu-latest
name: Get tag
outputs:
tag: ${{ steps.parse-tag.outputs.tag }}
steps:
- uses: actions/checkout@v3
- uses: aica-technology/.github/.github/actions/docker-tag-from-git@v0.6.1
id: parse-tag

build:
needs: [get-tag]
strategy:
matrix:
arch: [amd64, arm64]
include:
# FIXME (#33): high memory usage during build
- image: ubuntu-latest
- image: buildjet-8vcpu-ubuntu-2204-arm
arch: arm64

runs-on: ${{ matrix.image }}
name: Build and publish (${{ matrix.arch }})
steps:
- uses: actions/checkout@v3

- uses: aica-technology/.github/.github/actions/list-add-suffixes@v0.6.0
id: merge-tags
with:
list: ${{ needs.get-tag.outputs.tag }}
suffixes: ${{ matrix.arch }}
glue_separator: "-"

- uses: aica-technology/.github/.github/actions/ghcr-build@v0.6.1
with:
image_name: aica-technology/modulo
image_tags: ${{ steps.merge-tags.outputs.list }}
dockerfile_path: Dockerfile.ci
token: ${{ secrets.GITHUB_TOKEN }}

multi-arch:
runs-on: ubuntu-latest
name: Merge into a multi-arch image
needs: [get-tag, build]
steps:
- uses: aica-technology/.github/.github/actions/ghcr-manifest-merge@v0.6.1
with:
image_name: aica-technology/modulo
image_tags: ${{ needs.get-tag.outputs.tag }}
archs: amd64,arm64
token: ${{ secrets.GITHUB_TOKEN }}
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# CHANGELOG

Release Versions:

- [2.3.0](#230)
- [2.2.0](#220)
- [2.1.1](#211)
- [2.1.0](#210)

## 2.3.0

### July 25, 2023

Version 2.3.0 is a minor update to modulo that improves test coverage and adds a feature to publish outputs manually.
It also contains behind-the-scenes structural improvements to the build system and the CI.

### Changes

- feat(ci): add prebuilt modulo image akin to other internal ones (#36)
- Add and install component descriptions (#31)
- Apply AICA C++ style guide (#30)
- Add option to publish outputs manually instead of periodically (#23)
- Add unittests for modulo component service calls and triggers (#20)
- Extend testutils with C++ classes (#19)

## 2.2.0

### March 21, 2023
Expand Down
37 changes: 37 additions & 0 deletions Dockerfile.ci
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#syntax=docker/dockerfile:1.4.0
ARG CL_VERSION=v7.1.0
ARG ROS2_VERSION=humble
FROM ghcr.io/aica-technology/control-libraries:${CL_VERSION} as cl
FROM ghcr.io/aica-technology/ros2-ws:${ROS2_VERSION} as base
# setup the environment
USER ${USER}
ENV WORKSPACE ${HOME}/ws
WORKDIR ${WORKSPACE}
SHELL ["/bin/bash", "-l", "-c"]

# create a workspace
RUN source ${HOME}/ros2_ws/install/setup.bash && colcon build
# source the new workspace on login
RUN echo "source ${WORKSPACE}/install/setup.bash" | cat - ${HOME}/.bashrc > tmp && mv tmp ${HOME}/.bashrc
# install deps
COPY --from=cl / /
# install sources
COPY --chown=${USER}:${USER} ./source ${WORKSPACE}/src

FROM base as development

FROM base as build
ARG TARGETPLATFORM
RUN --mount=type=cache,target=./build,id=${TARGETPLATFORM},uid=1000 \
sudo apt-get update && rosdep update \
&& rosdep install --from-paths src --ignore-src -r -y \
--skip-keys "ros2_control ros2_controllers controller_interface hardware_interface controller_manager" \
&& sudo rm -rf /var/lib/apt/lists/* \
&& colcon build

FROM build as test
ARG TARGETPLATFORM
RUN --mount=type=cache,target=./build,id=${TARGETPLATFORM},uid=1000 colcon test

FROM scratch as production
COPY --from=build /home/ros2/ws/install /colcon
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.2.0
2.3.0
2 changes: 1 addition & 1 deletion doxygen/doxygen.conf
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ PROJECT_NAME = "Modulo"
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = 2.2.0
PROJECT_NUMBER = 2.3.0

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
Expand Down
2 changes: 1 addition & 1 deletion source/modulo_component_interfaces/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>modulo_component_interfaces</name>
<version>2.2.0</version>
<version>2.3.0</version>
<description>Interface package for communicating with modulo components through the ROS framework</description>
<maintainer email="enrico@aica.tech">Enrico Eberhard</maintainer>
<license>GPLv3</license>
Expand Down
8 changes: 5 additions & 3 deletions source/modulo_components/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ ament_auto_find_build_dependencies()
include_directories(include)

ament_auto_add_library(${PROJECT_NAME} SHARED
${PROJECT_SOURCE_DIR}/src/ComponentInterface.cpp
${PROJECT_SOURCE_DIR}/src/Component.cpp
${PROJECT_SOURCE_DIR}/src/LifecycleComponent.cpp)

# Install Python modules
ament_python_install_package(${PROJECT_NAME} SCRIPTS_DESTINATION lib/${PROJECT_NAME})

# Install descriptions
install(DIRECTORY ./component_descriptions
DESTINATION .)

if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_cmake_pytest REQUIRED)
Expand All @@ -41,8 +44,7 @@ if(BUILD_TESTING)

ament_add_gtest(test_modulo_components ${TEST_CPP_SOURCES})
target_include_directories(test_modulo_components PRIVATE include)
target_link_libraries(test_modulo_components ${PROJECT_NAME} state_representation clproto)
target_compile_definitions(test_modulo_components PRIVATE TEST_FIXTURES="${CMAKE_CURRENT_SOURCE_DIR}/test/fixtures/")
target_link_libraries(test_modulo_components ${PROJECT_NAME})

# prevent pluginlib from using boost
target_compile_definitions(test_modulo_components PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "Component",
"description": {
"brief": "A wrapper for rclcpp::Node to simplify application composition through unified component interfaces.",
"details": "This class is intended for direct inheritance to implement custom components that perform one-shot or externally triggered operations."
},
"virtual": true,
"registration": "modulo_components::Component",
"inherits": "",
"parameters": [
{
"display_name": "Period",
"description": "The time interval in seconds for all periodic callbacks",
"parameter_name": "period",
"parameter_type": "double",
"default_value": "0.1"
}
],
"predicates": [
{
"display_name": "In error state",
"description": "True if the component is in error state",
"predicate_name": "in_error_state"
},
{
"display_name": "Is finished",
"description": "True if the on_execute_callback() method of one-shot components successfully finished",
"predicate_name": "is_finished"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "Lifecycle Component",
"description": {
"brief": "A wrapper for rclcpp_lifecycle::LifecycleNode to simplify application composition through unified component interfaces while supporting lifecycle states and transitions.",
"details": "This class is intended for direct inheritance to implement custom state-based components that perform different behaviors based on their state and on state transitions."
},
"virtual": true,
"registration": "modulo_components::LifecycleComponent",
"inherits": "",
"parameters": [
{
"display_name": "Period",
"description": "The time interval in seconds for all periodic callbacks",
"parameter_name": "period",
"parameter_type": "double",
"default_value": "0.1"
}
],
"predicates": [
{
"display_name": "In error state",
"description": "True if the component is in error state",
"predicate_name": "in_error_state"
},
{
"display_name": "Is unconfigured",
"description": "True if the component is in an unconfigured state, either through construction or cleanup transition",
"predicate_name": "is_unconfigured"
},
{
"display_name": "Is inactive",
"description": "True if the component is in an inactive state, either through the configuration or deactivation transition",
"predicate_name": "is_inactive"
},
{
"display_name": "Is active",
"description": "True if the component is in an active state, executing the step function periodically",
"predicate_name": "is_active"
},
{
"display_name": "Is finalized",
"description": "True if component is in a finalized state, either through the shutdown or error transition",
"predicate_name": "is_finalized"
}
]
}
31 changes: 13 additions & 18 deletions source/modulo_components/include/modulo_components/Component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ class Component : public ComponentInterface<rclcpp::Node> {
* @param data Data to transmit on the output signal
* @param default_topic If set, the default value for the topic name to use
* @param fixed_topic If true, the topic name of the output signal is fixed
* @param publish_on_step If true, the output is published periodically on step
*/
template<typename DataT>
void add_output(
const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::string& default_topic = "",
bool fixed_topic = false
bool fixed_topic = false, bool publish_on_step = true
);

private:
Expand Down Expand Up @@ -93,11 +94,11 @@ class Component : public ComponentInterface<rclcpp::Node> {
template<typename DataT>
inline void Component::add_output(
const std::string& signal_name, const std::shared_ptr<DataT>& data, const std::string& default_topic,
bool fixed_topic
bool fixed_topic, bool publish_on_step
) {
using namespace modulo_core::communication;
try {
auto parsed_signal_name = this->create_output(signal_name, data, default_topic, fixed_topic);
auto parsed_signal_name = this->create_output(signal_name, data, default_topic, fixed_topic, publish_on_step);
auto topic_name = this->get_parameter_value<std::string>(parsed_signal_name + "_topic");
RCLCPP_DEBUG_STREAM(this->get_logger(),
"Adding output '" << parsed_signal_name << "' with topic name '" << topic_name << "'.");
Expand All @@ -107,49 +108,43 @@ inline void Component::add_output(
auto publisher = this->create_publisher<std_msgs::msg::Bool>(topic_name, this->qos_);
this->outputs_.at(parsed_signal_name) =
std::make_shared<PublisherHandler<rclcpp::Publisher<std_msgs::msg::Bool>, std_msgs::msg::Bool>>(
PublisherType::PUBLISHER, publisher
)->create_publisher_interface(message_pair);
PublisherType::PUBLISHER, publisher)->create_publisher_interface(message_pair);
break;
}
case MessageType::FLOAT64: {
auto publisher = this->create_publisher<std_msgs::msg::Float64>(topic_name, this->qos_);
this->outputs_.at(parsed_signal_name) =
std::make_shared<PublisherHandler<rclcpp::Publisher<std_msgs::msg::Float64>, std_msgs::msg::Float64>>(
PublisherType::PUBLISHER, publisher
)->create_publisher_interface(message_pair);
PublisherType::PUBLISHER, publisher)->create_publisher_interface(message_pair);
break;
}
case MessageType::FLOAT64_MULTI_ARRAY: {
auto publisher = this->create_publisher<std_msgs::msg::Float64MultiArray>(topic_name, this->qos_);
this->outputs_.at(parsed_signal_name) =
std::make_shared<PublisherHandler<rclcpp::Publisher<std_msgs::msg::Float64MultiArray>,
std_msgs::msg::Float64MultiArray>>(
PublisherType::PUBLISHER, publisher
)->create_publisher_interface(message_pair);
this->outputs_.at(parsed_signal_name) = std::make_shared<
PublisherHandler<
rclcpp::Publisher<std_msgs::msg::Float64MultiArray>, std_msgs::msg::Float64MultiArray>>(
PublisherType::PUBLISHER, publisher)->create_publisher_interface(message_pair);
break;
}
case MessageType::INT32: {
auto publisher = this->create_publisher<std_msgs::msg::Int32>(topic_name, this->qos_);
this->outputs_.at(parsed_signal_name) =
std::make_shared<PublisherHandler<rclcpp::Publisher<std_msgs::msg::Int32>, std_msgs::msg::Int32>>(
PublisherType::PUBLISHER, publisher
)->create_publisher_interface(message_pair);
PublisherType::PUBLISHER, publisher)->create_publisher_interface(message_pair);
break;
}
case MessageType::STRING: {
auto publisher = this->create_publisher<std_msgs::msg::String>(topic_name, this->qos_);
this->outputs_.at(parsed_signal_name) =
std::make_shared<PublisherHandler<rclcpp::Publisher<std_msgs::msg::String>, std_msgs::msg::String>>(
PublisherType::PUBLISHER, publisher
)->create_publisher_interface(message_pair);
PublisherType::PUBLISHER, publisher)->create_publisher_interface(message_pair);
break;
}
case MessageType::ENCODED_STATE: {
auto publisher = this->create_publisher<modulo_core::EncodedState>(topic_name, this->qos_);
this->outputs_.at(parsed_signal_name) =
std::make_shared<PublisherHandler<rclcpp::Publisher<modulo_core::EncodedState>, modulo_core::EncodedState>>(
PublisherType::PUBLISHER, publisher
)->create_publisher_interface(message_pair);
PublisherType::PUBLISHER, publisher)->create_publisher_interface(message_pair);
break;
}
}
Expand Down
Loading
Loading