ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Composition just means that you provide the node (as a class that inherits from node) and someone else (like a boilerplate main function or composition executable) provide the threading with an executor of some sort.

Composition uses executors to execute one or more nodes in a thread (in the case of SingleThreadedExecutor) or in multiple threads (in the case of MultiThreadedExecutor).

The single threaded executor just runs in the thread in which you call executor.spin().

The multi threaded executor creates threads using std::thread and then dispatches work to them from the thread in which you call executor.spin().

So if you use the composition demo (https://github.com/ros2/demos/tree/master/composition) then it will most likely be using a single threaded executor in the main thread, e.g.:

https://github.com/ros2/demos/blob/7dd5ce6ac63c04fdb528705b2766d8d4c1d49cb4/composition/src/api_composition.cpp#L76

But there's no reason for that really, another composition example might use a multi threaded executor or a single threaded executor in a thread created with pthread.

In fact, if you used a multi threaded executor to load one or more component nodes (again nodes implemented as a sub class of rclcpp::Node), then you're using most of the things you listed: composition, MultiThreadedExecutor, std::thread, and pthread (because std::thread is probably implemented with pthread on your machine).

I'll also mention that the single and multi threaded executor are just the two built in executors, but you can create your own if you'd like to do something different with the creation of threads, or scheduling of callbacks, or the distribution of callbacks to certain threads, etc...


My recommendation is put all of your "business logic" for your node in one set of source files and implement it as a sub class of rclcpp::Node, but avoid creating any executors or calling spin anywhere. And in a separate file, you can have one of these "boilerplate main" functions which creates an executor, creates an instance of your node, adds your node to the executor, and then calls spin().

Then in the future you'll easily be able to take advantage of composition because the only thing anyone needs to do in order to compose your node into a process is instantiate it and add it to an executor.