For now the composition API implementation is not in ROS2 base repos, so we use the customized rclpy, ros2cli for demonstration. I assume you have a underlay ready to work, I'd personally recommend using Docker image ros2:nightly-dev
to test it to make a minimal impact of your own environment.
First prepare the workspace and related repos
$ mkdir -p ~/rclpy_composition_ws/src
$ cd ~/rclpy_composition_ws/src
$ git clone --branch composition-api-pr https://github.com/crystaldust/rclpy
$ git clone --branch composition-api-pr https://github.com/crystaldust/ros2cli
$ git clone --branch master https://github.com/crystaldust/rcl_component_searchers
$ git clone --branch composition-api https://github.com/crystaldust/rclpy_composition_example
$ cd ../
Then build and source the environment script, use which ros2
command to check if our customized cli tool is being used:
$ colcon build
$ source install/setup.bash
$ which ros2
/root/rclpy_composition_ws/install/ros2cli/bin/ros2 # Make sure it's not /opt/ros/<distro>/bin/ros2
Test if ros2cli can recognize the rclpy_components:
$ ros2 component types
...
rclcpp_components/composition
composition::Talker
composition::Listener
composition::NodeLikeListener
composition::Server
composition::Client
rclpy_components/py_composition
py_composition::Talker
py_composition::Listener
A little difference here is, the composition types will begin with a language mark(the rclcpp_components
, rclpy_components
), let's run a component_container:
$ ros2 run rclpy_components component_container
Open a new session and call the component commands:
$ source ~/rclpy_composition_ws/install/setup.bash # Don't forget to update the environment
$ ros2 component list
/PyComponentManager
$ ros2 component load /PyComponentManager py_composition py_composition::Talker
Loaded component 1 into '/PyComponentManager' container node as '/talker'
$ ros2 component load /PyComponentManager py_composition py_composition::Listener
Loaded component 2 into '/PyComponentManager' container node as '/listener'
Then go back to the previous session, the container will display the Talker and Listener components' logs:
[INFO] [1592908811.949662551] [Talker]: Pulibhsing Hello from composition talker 0
[INFO] [1592908812.918946940] [Talker]: Pulibhsing Hello from composition talker 1
[INFO] [1592908813.917545186] [Talker]: Pulibhsing Hello from composition talker 2
[INFO] [1592908814.918682372] [Talker]: Pulibhsing Hello from composition talker 3
[INFO] [1592908814.922476919] [Listener]: I heard Hello from composition talker 3
[INFO] [1592908815.918818523] [Talker]: Pulibhsing Hello from composition talker 4
[INFO] [1592908815.920822898] [Listener]: I heard Hello from composition talker 4
If you look into the setup.py
file you'll find the entry_points parameter for composition:
setup(
name=package_name,
version='0.0.0',
packages=[package_name],
entry_points={
'rclpy_components': [
'py_composition::Talker = rclpy_composition_example.talker_component:Talker',
'py_composition::Listener = rclpy_composition_example.listener_component:Listener',
]
},
)
Here we declares a couple of rclpy_components
entry points which will let the ros2cli component verb find the entry point values. Then when loading components, the component container will be able to access the actual class reference, instantiate it and put the instance into the executor.