-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial 5: Using the Component Manager
Note: All examples shown in this tutorial can be found and replicated via Temoto Tutorials repository.
Component Manager is a ROS node, which maintains information about components (including published/subscribed topics, package names) and can dynamically compose them based on component templates (i.e. pipes). Components are ROS based programs (nodes/launch files) which provide sensing or data processing functionalities. A component template outlines the structure of a composed component, e.g., a combination of a manipulator arm and a force-torque sensor with compliance controller. Templates can then be used to dynamically combine individual components and replace faulty ones. Component Manager utilizes Process Manager to bring up the components.
The description of each component (including published/subscribed topics, package name, etc) is outlined in the components.yaml file.
For example, here is a YAML description of a usb_cam-based 2D camera driver:
- component_name: "Forward-facing camera"
component_type: "2d_camera"
package_name: "tutorials_temoto_config"
executable: "usb_cam_remappable.launch"
output_topics:
camera_data: "usb_cam/image_raw"
camera_data_compressed: "usb_cam/image_raw/compressed"
camera_info: "usb_cam/camera_info"
required_parameters:
frame_id: "camera_link"
video_device: "/dev/video0"This is a simple demonstration of the Component Manager (CM) from client's perspective. In this example the CM is used to load a camera, as outlined in the example YAML descripition above, but you can modify the example to load other components that may relate better to your use-case. Here's the whole C++ demo application (explanations will follow):
#include "ros/ros.h"
#include "temoto_component_manager/component_manager_interface.h"
void componentFailureCallback(temoto_component_manager::LoadComponent load_component_msg
, temoto_resource_registrar::Status status_msgs)
{
ROS_WARN_STREAM("The following component stopped unexpectedly\n" << load_component_msg.request);
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "component_manager_client");
ros::AsyncSpinner spinner(4);
spinner.start();
temoto_component_manager::ComponentManagerInterface cmi(true);
cmi.registerComponentStatusCallback(componentFailureCallback);
ROS_INFO("Loading 2d_camera");
auto responded_topics = cmi.startComponent("2d_camera");
for (const auto& topic : responded_topics.getOutputTopics())
{
ROS_INFO_STREAM("* " << topic.first << ": " << topic.second);
}
ros::Duration(30).sleep();
ROS_INFO("Unloading 2d_camera");
cmi.stopComponent("2d_camera", "", "");
return 0;
}For this demo you need a usb camera (laptop's integrated camera or a webcam will work just fine) and the usb_cam package installed. If you don't have the package already then:
sudo apt install ros-noetic-usb-cam# Launch TeMoto
roslaunch tutorials_temoto_config temoto.launch temoto_namespace:=my_temoto# Run the component_manager_client example
rosrun tutorials_temoto_config component_manager_client __ns:=my_temotoYou should see the following output in the terminal:
[ INFO] [1681746517.606458622]: Loading 2d_camera
[ INFO] [1681746517.612016942]: * camera_data: /my_temoto/usb_cam/image_raw
[ INFO] [1681746517.612037191]: * camera_data_compressed: /my_temoto/usb_cam/image_raw/compressed
[ INFO] [1681746517.612049975]: * camera_info: /my_temoto/usb_cam/camera_info
[ INFO] [1681746547.612175510]: Unloading 2d_cameraMany laptops include a small LED by the camera to let you know that the resource is being used by an application. You can check to see if this light is active while the component is running.
temoto_component_manager::ComponentManagerInterface cmi(true);Create CM Interface object that provides a simplified API for communicating with the Component Manager. The boolean "true", that's passed to the constructor of CM interface tells it whether it should be initialised immediately, or that's done later by the user.
cmi.registerComponentStatusCallback(componentFailureCallback);You can register a custom routine (not required) where component updates or failures are reported.
auto responded_topics = cmi.startComponent("2d_camera");Use the
startComponentmethod to load a component based on its type (e.g., 2d_camera). After the component has been loaded, the method will return an object that contains the list of published (output) and subscribed (input) topics, which you can use to dynamically subrscribe/publish to.
for (const auto& topic : responded_topics.getOutputTopics()) { ROS_INFO_STREAM("* " << topic.first << ": " << topic.second); }Just an example how you can accesss the output topics. Similarly,
getInputTopicsmethod can be used to access the input topics.
cmi.stopComponent("2d_camera", "", "");Stop the component. Since this particular demo application is finished at that point, it is not strictly necessary to explicitly stop the component, as the destructor of
cmiobject automatically stops all loaded components.
As a standard with ROS packages, you have to modify the CMakeLists.txt and package.xml files
Add temoto_component_manager to the find_package macro and declare it as a dependency of your custom package. The simplest way to make your custom targets (executables, libraries) link with temoto_component_manager is to use the catkin_LIBRARIES variable:
find_package(catkin REQUIRED COMPONENTS
<other-packages>
temoto_component_manager
)
catkin_package(
...
CATKIN_DEPENDS <other-deps> temoto_component_manager
)
add_executable(my_custom_exec
src/my_custom_exec.cpp
)
add_dependencies(my_custom_exec
${catkin_EXPORTED_TARGETS}
${${PROJECT_NAME}_EXPORTED_TARGETS}
)
target_link_libraries(my_custom_exec
${catkin_LIBRARIES}
)Add temoto_component_manager as a dependency:
<depend>temoto_component_manager</depend>Pipe management is the second main feature of the Component Manager. Pipes are composed of segments, i.e., components, that sequentially pass data from one segment to another. For example Figure 2. depicts a pipe which tracks objects based on filtered video data.
The pipes are described via pipes.yaml which has the following structure:
-
pipe_category_A
- pipe_method_0
- segment_0_1
- segment_0_2
- segment_0_3
- pipe_method_1
- segment_1_1
- segment_1_2
- ...
- pipe_method_0
-
pipe_category_B
- ...
where
- pipe category indicates the generic purpose of the pipes outlined under it
- method allows to define different alternatives for achieving the same pipe functionality
- segment describes what kind of component should be used for a particular pipe method
Each segment outlines the structure of a component but without mentioning any specific topic names, just the component type and topic types:
-
segment_type: "component_type"
- input_topic_types:
- topic_type_0
- topic_type_1
- output_topic_types:
- topic_type_2
- topic_type_3
- input_topic_types:
Here is an example of an AR tag tracking pipe
ar_tag_tracking:
- method:
- segment_type: "2d_camera"
required_parameters:
- frame_id
output_topic_types:
- camera_info
- camera_data
- segment_type: "ar_tag_tracker"
required_parameters:
- frame_id
input_topic_types:
- camera_info
- camera_data
output_topic_types:
- visualization_data
- tag_dataThe temoto_tutorials repo contains an example setup for demonstrating components. In this demonstration, three components will be combined into a pipe where each component is subscribing and publishing std_msgs::string messages. The output of the final component within the pipe is a sentence, which reads "The pipe is working like it is supposed to" and "The data is flowing properly". The point is that each component has added only a part of the sentence, thus demonstrating that the pipe is truly working like a pipeline.
The components.yaml contains three component descriptions named "String spammer 0", "String spammer 1" and "String spammer 2". The source code can be found here. Now the pipes.yaml outlines how these components should be combined. Note that only component and topic types are used and no specific names are mentioned. This allows to dynamically resolve to any alternative if necessary.
Try the thing out by first:
roslaunch tutorials_temoto_config temoto.launch temoto_namespace:=my_temotoand then:
roslaunch ta_component_pipe_test invoke_action.launch wake_word:=my_temotoThis action is programmed to run for 20 seconds and then it shuts down. While it runs check the rosnode list and rostopic list to see how pipes are assembled via ROS topics.