Basic C++ Nodes to understand essential concepts and the build procedure for a C++ package.
Link to the README of the
srcfolder here
- Basic Nodes (C++)
- Table of contents
- Creating this package
- Foreword
- Contents
- Nodes
- Simple Hello World
- Simple Publisher
- Simple Subscriber
- Simple Service Server
- Simple Service Client
- Simple Action Server
- Simple Action Client
- Simple Parameter Node
- Launch1 Publisher
- Launch1 Subscriber
- Launch1 Parameters
- Simple Dynamic Reconfiguration Server
- Simple Dynamic Reconfiguration Client
- Simple Library Node
- Basic Math Node
- Services
- Actions
- YAML Files
- Launch Files
- Dynamic Reconfiguration Files
- Reference
This package was created using the following commands
cd ~/ros_workspaces/learning_ws/src
catkin_create_pkg cpp_basic_nodes roscppThis is the first package and hence things are described in a little more detail here. The source code has comments describing the contents that are new.
When reading this file, you may either traverse from top to bottom (recommended for beginners) or navigate through table of contents. If you are a beginner, you're suggested to navigate the package using the contents section. In the Nodes section, the nodes are described starting with a table (to lead you to the source code). Same is done for other sections hereon.
Make sure you know how to build a package before proceeding.
Suggested order of traversal for the items in this package (specially for beginners)
| S. No. | Name | Link | Description |
|---|---|---|---|
| 1 | Hello World | Nodes > Simple Hello World | Prints Hello, World! |
| 2 | Publisher (Simple) | Nodes > Simple Publisher | Publish messages |
| 3 | Subscriber (Simple) | Nodes > Simple Subscriber | Subscribe to messages |
| 4 | Creating AddAllFloat64Numbers_cpp service |
Services > AddAllFloat64Numbers_cpp | Creating and building your own service (.srv file) |
| 5 | Service Server (Simple) | Nodes > Simple Service Server | Server for the service AddAllFloat64Numbers_cpp |
| 6 | Service Client (Simple) | Nodes > Simple Service Client | Client for the service AddAllFloat64Numbers_cpp |
| 7 | Creating CountNumbers_cpp action |
Actions > CountNumbers_cpp | Creating and building your own action (.action file) |
| 8 | Action Server (Simple) | Nodes > Simple Action Server | Server for the action CountNumbers_cpp |
| 9 | Action Client (Simple) | Nodes > Simple Action Client | Client for the action CountNumbers_cpp |
| 10 | YAML ROS Parameter | YAML Files > Params1 | Simple YAML file which can be loaded on the ROS Parameter Server (.yaml file) |
| 11 | Parameter Node (Simple) | Nodes > Simple Parameter Node | Accessing parameters on the parameter server |
| 12 | Publisher for Launch1 |
Nodes > Launch1 Publisher | A publisher created for a launch file |
| 13 | Subscriber for Launch1 |
Nodes > Launch1 Subscriber | A subscriber created for a launch file |
| 14 | Parameters Node for Launch1 |
Nodes > Launch1 Parameters | Accessing parameters, spawned through a launch file |
| 15 | YAML file 1 for Launch1 |
YAML Files > l1_params1 | A YAML file to load parameters into a launch file |
| 16 | YAML file 2 for Launch1 |
YAML Files > l1_params2 | A YAML file to load parameters into a launch file |
| 17 | Launch1 launch file |
Launch Files > Launch1 | A .launch file to simplify launching everything tagged as Launch1 |
| 18 | FirstDR Dynamic Reconfiguration file |
Dynamic Reconfiguration Files > FirstDR | Creating a .cfg file for parameters that can be dynamically reconfigured |
| 19 | Dynamic Reconfiguration Server (Simple) | Nodes > Simple Dynamic Reconfiguration Server | Creating a node that will contain the modifiable parameters for dynamic reconfiguration FirstDR |
| 20 | Dynamic Reconfiguration Client (Simple) | Nodes > Simple Dynamic Reconfiguration Client | Creating a client node that will modify parameters of FirstDR on the server |
| 21 | Simple Library Node | Nodes > Simple Library Node | A node that uses simple_library from package basic_cpp_libs (a simple library) |
| 22 | Basic Math Node | Nodes > Basic Math Node | A node that uses basic_math library from package basic_cpp_libs (a relatively more sophisticated library) |
Nodes declared in this package
| Field | Value |
|---|---|
| Node name | simple_hello_world |
| Code | src/simple_hello_world.cpp |
Node prints Hello, World! and different levels of logging messages.
To build the node, add the following in the CMakeLists.txt file in the package
- Go to the
Buildsection (it must be decorated with "Build" heading)-
Scroll to the
add_executablefunctionAdd the following lines immediately after the comment block
add_executable(simple_hello_world src/simple_hello_world.cpp)
This will create an executable named
simple_hello_worldfrom the source codesimple_hello_world.cpp.More on
add_executableinCMakeLists.txthere -
Scroll to the
target_link_librariesfunctionAdd the ROS libraries in this function. The executable may need function calls from the default libraries (it depends on these libraries). You can use the
${catkin_LIBRARIES}variable to get the default libraries.target_link_libraries(simple_hello_world ${catkin_LIBRARIES})More on
target_link_librariesinCMakeLists.txthere
-
After that, build the package by running catkin_make in the workspace directory. After a successful build process, you must see an executable named simple_hello_world in the directory devel/lib/cpp_basic_nodes (inside the workspace). This means that the workspace stores all the executables in the devel folder.
A similar procedure shall be followed for other nodes, so only the function names shall be mentioned hereon.
First, make sure that roscore is running and that the package has been built successfully and can be found using rospack find
rospack find cpp_basic_nodesShould return the path to the package. To run the node, run
rosrun cpp_basic_nodes simple_hello_worldThis should run the node. Inspect the output of the following
rosnode listThis shall show the node as /hello_world_simple, that is the name used in ros::init function in the source code. This means that the name of the node during runtime can be different from the name of the executable.
Hereon, only the rosrun command (the bare minimum) shall be described.
After that, try running the node as
rosrun cpp_basic_nodes simple_hello_world arg1 arg2 arg3You may kill the node using
rosnode kill /hello_world_simpleAfter running the node, a few observations can be made:
- The debug messages do not appear, but information level and above messages do appear.
- Proper logging etiquette is observed. Do not use
coutto log things. - The first argument passed to any executable is the full path of the executable, followed by arguments passed during the call.
- The second debug message was visible (changed logger level in code).
- You have successfully run your first C++ ROS node.
| Field | Value |
|---|---|
| Node name | simple_cpp_publisher |
| Code | src/simple_publisher.cpp |
Node publishes a message on a topic named /simple_cpp_publisher/hello_str. Demonstrates publishing messages on a topic and name scoping.
In the CMakeLists.txt, add the following
add_executable(simple_cpp_publisher src/simple_publisher.cpp)and
target_link_libraries(simple_cpp_publisher ${catkin_LIBRARIES})Then, run catkin_make in the workspace folder.
To run the node, first run roscore, then
rosrun cpp_basic_nodes simple_cpp_publisherNow, run
rostopic listYou must see /simple_cpp_publisher/hello_str in the output. This is because the node handle was passed the ~ in the source code (namespace has become local to the node). If you rebuild the node after removing ~, the name would then become /hello_str (that is, use ros::NodeHandle nh; instead of ros::NodeHandle nh("~");).
You can inspect the contents of the messages being published by running
rostopic echo /simple_cpp_publisher/hello_strThis would echo messages from the point where the command was called. You are encouraged to experiment and understand things before proceeding further (same is true for everything hereon).
Kill the nodes using rosnode kill commands.
| Field | Value |
|---|---|
| Node name | simple_cpp_subscriber |
| Code | src/simple_subscriber.cpp |
Node subscribes to a topic named /simple_cpp_subscriber/subs_str. Demonstrates subscribing to messages received on a topic.
In the CMakeLists.txt, add the following lines at appropriate places
add_executable(simple_cpp_subscriber src/simple_subscriber.cpp)target_link_libraries(simple_cpp_subscriber ${catkin_LIBRARIES})Then run catkin_make in the workspace folder.
To run the node, first run roscore, then
rosrun cpp_basic_nodes simple_cpp_subscriberNow, after running
rostopic listYou must see a topic named /simple_cpp_subscriber/subs_str has been created. Get more information about it using rostopic info.
To publish a message on that topic at a particular frequency, run
rostopic pub /simple_cpp_subscriber/subs_str std_msgs/String "data: 'Hello World'" -r 0.2This would publish a message with data as Hello World every 5 seconds (0.2 Hz is the rate passed).
You may even experiment with remapping arguments to make the publisher that we had created earlier to publish messages to /simple_cpp_subscriber/subs_str instead of its default programmed publishing topic /simple_cpp_publisher/hello_str. To do that, run the following command
rosrun cpp_basic_nodes simple_cpp_publisher /simple_cpp_publisher/hello_str:=/simple_cpp_subscriber/subs_strRemember that the publisher actually publishes at a programmed rate of 0.5 Hz. If you have the previous rostopic pub node still running, there actually are two nodes publishing and one node subscribing to the topic. Run the following command
rosrun rqt_graph rqt_graphWould produce the following output
You may further experiment with the code to see how the output changes. Most notably, you can do the following
- Try creating a large enough delay in the subscriber callback that messages accumulate. Then see what happens. More about a standard way of creating a delay on the current thread here. You can further experiment here with different queue sizes.
| Field | Value |
|---|---|
| Node name | simple_cpp_service_server |
| Code | src/simple_service_server.cpp |
| Service | AddAllFloat64Numbers_cpp.srv |
Before this node, you have to understand declaring and building services. Check AddAllFloat64Numbers_cpp section for that. This node demonstrates how to create a service server.
In the CMakeLists.txt, add the following lines at appropriate places
-
Add the
add_executablefunctionadd_executable(simple_cpp_service_server src/simple_service_server.cpp)
-
Add the
add_dependenciesfunctionadd_dependencies(simple_cpp_service_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
Notice the
${${PROJECT_NAME}_EXPORTED_TARGETS}dependency, which is required for the dependency on the package messages, services and actions declared. This means that you actually do not even need to build those messages before you use them in the nodes of the same package. The dependency order will be automatically set to build messages and underlying headers before using them to build the nodes.Check out this example on roswiki for more
-
Add the
target_link_librariesfunctiontarget_link_libraries(simple_cpp_service_server ${catkin_LIBRARIES})
Then run catkin_make in the workspace folder.
To run this node, run roscore first. To run the node, run
rosrun cpp_basic_nodes simple_cpp_service_serverAfter this, the rosservice tool can be used to find if the service is running
rosservice listTo call the service, a service client could be used or the call can also be made through the command line. Try running
rosservice call /simple_cpp_service_server/add_numbers "data:
- 12.5
- 37.25
- 100.75
- -20.3"When you used tab completion, the first data value would be filled with 0. Just remove the ending " and continue on by typing an enter (or even Ctrl-V Ctrl-J would do). Usually after pressing enter, another prompt shows up to indicate completing the string, that is stored in $PS2 (usually a >). After pressing enter upon completing the string with ", an output like this must appear
sum: 130.2| Field | Value |
|---|---|
| Node name | simple_cpp_service_client |
| Code | src/simple_service_client.cpp |
| Service | AddAllFloat64Numbers_cpp.srv |
Before this node, you have to understand declaring and building services. Check AddAllFloat64Numbers_cpp section for that. This node demonstrates how to create a service client. It will call a service, so the service server needs to be present first. A simple service server is demonstrated above.
In the CMakeLists.txt, add the following line at appropriate places
-
Add the
add_executablefunctionadd_executable(simple_cpp_service_client src/simple_service_client.cpp)
-
Add the
add_dependenciesfunctionadd_dependencies(simple_cpp_service_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
Note that the
${${PROJECT_NAME}_EXPORTED_TARGETS}tag is needed for using the service generated -
Add the
target_link_librariesfunctiontarget_link_libraries(simple_cpp_service_client ${catkin_LIBRARIES})
To run this node, run roscore first. Additionally, a service server (servicing the service mentioned in the node, bearing the name /simple_cpp_service_server/add_numbers) must be running. This package has the corresponding service server node. To run that node, run
rosrun cpp_basic_nodes simple_cpp_service_serverEnsure that the service /simple_cpp_service_server/add_numbers is running (using rosservice list)
To run this node, run a command like what's shown below (you can use any numbers in the argument)
rosrun cpp_basic_nodes simple_cpp_service_client 60 4 0.5 -98.7If everything's gone right, the sum must return -34.2 for the given numbers.
| Field | Value |
|---|---|
| Node name | simple_cpp_action_server |
| Code | src/simple_action_server.cpp |
| Action | action/CountNumbers_cpp.action |
Before this node, you have to understand how .action files are build, check Actions > CountNumbers_cpp for that. This node shows how to create an action server.
In the CMakeLists.txt, add the following lines at appropriate places
-
Add the
add_executablefunctionadd_executable(simple_cpp_action_server src/simple_action_server.cpp)
-
Add the
add_dependenciesfunction for the action headers (the tags will be generated automatically)add_dependencies(simple_cpp_action_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
-
Add the
target_link_librariesfunctiontarget_link_libraries(simple_cpp_action_server ${catkin_LIBRARIES})
After that, run catkin_make in the workspace folder. The node will be generated. In order to use it, you'll need an action client. However, you can use direct messaging to see the underlying mechanism.
To run this node, run roscore first. To run the node, run
rosrun cpp_basic_nodes simple_cpp_action_serverNote that actions actually use messages to communicate. To see the messages for the action, run the following command
rostopic list | grep -E "/simple_cpp_action_server/count_numbers/"You'll see messages for cancel, feedback, goal, result and status. To test and see how the actionlib mechanism may work, run these commands in separate terminals that you can see at the same time
rostopic echo /simple_cpp_action_server/count_numbers/result
rostopic echo /simple_cpp_action_server/count_numbers/feedback
rostopic echo /simple_cpp_action_server/count_numbers/statusThen, in another terminal, we will publish a message to the goal topic. You could use the command below
rostopic pub /simple_cpp_action_server/count_numbers/goal cpp_basic_nodes/CountNumbers_cppActionGoal "header:
seq: 0
stamp:
secs: 0
nsecs: 0
frame_id: ''
goal_id:
stamp:
secs: 0
nsecs: 0
id: ''
goal:
target_number: 10
del_ms: 1000" -1The above command will tell the server to count up to 10 with a delay of 1000 ms between each count. After everything is done, the output must look somewhat like below
The status is being displayed on the bottom right, with the feedback on top and result left to it. The main node is at the top left and under it is the publisher to goal.
As seen in the code, we have only programmed the logic of execution, and everything on the communication side has been handled by the actionlib package (which is why we needed it as a dependency). However, the method that we used here is not a proper one used to call actions (notice that we did not fill many fields in the goal publisher command above, namely header and goal ID). For that, we need to create an action client. Then, actionlib would handle the publishing part as well, we'd only have to give it the goal. For that, check out the Simple Action Client below.
| Field | Value |
|---|---|
| Node name | simple_cpp_action_client |
| Code | src/simple_action_client.cpp |
| Action | action/CountNumbers_cpp.action |
Before this node, you have to understand how .action files are build, check Actions > CountNumbers_cpp for that. This node shows how to create an action client. A simple action server that can be used with this client is demonstrated above.
Add the following functions at the appropriate places in the CMakeLists.txt file.
add_executable(simple_cpp_action_client src/simple_action_client.cpp)
add_dependencies(simple_cpp_action_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(simple_cpp_action_client ${catkin_LIBRARIES})And then run catkin_make in the workspace folder
First run roscore. In order to run an action client, an action server has to be spawned first, run the following
rosrun cpp_basic_nodes simple_cpp_action_serverNow, you can run the client using (run this on a different terminal window)
rosrun cpp_basic_nodes simple_cpp_action_client 10 500This must produce the following output
You are encouraged to inspect the contents of the underlying messages as discussed in the simple action server.
| Field | Value |
|---|---|
| Node name | simple_cpp_parameter_node |
| Code | src/simple_parameter_server.cpp |
Before this, it is suggested that you get a hands on experience with parameters. You must also understand the notion of storing and loading parameters through YAML files. Check out YAML Files > Params for understanding YAML files and parameter server in ROS.
Add the following functions at the appropriate places in the CMakeLists.txt file.
add_executable(simple_cpp_parameter_node src/simple_parameter_server.cpp)
target_link_libraries(simple_cpp_parameter_node ${catkin_LIBRARIES})And then run catkin_make in the workspace folder
First, run roscore, then run this node using
rosrun cpp_basic_nodes simple_cpp_parameter_nodeThe output must consist of the contents of existing parameters (some keys/parameters may not be found and that's okay, you can roskill the node now). It must also have created another parameter on the server by the name of /custom_cpp_parameter, check it using rosparam get (this will persist even after the node as the resource is on the ROS Master). You must now load the Params1.yaml file into the parameter server and then rerun the node.
rosparam load `rospack find cpp_basic_nodes`/yaml/Params1.yaml
rosrun cpp_basic_nodes simple_cpp_parameter_nodeNow, the node must display the values of the parameters on the parameter server having previously unidentified keys. Most importantly, a junk parameter with the key junk_parameter must have been loaded by the YAML file (through rosparam load command) and then deleted by this node (check using rosparam list before running the node and after running the node, with the YAML file freshly loaded this time).
| Field | Value |
|---|---|
| Node name | launch1_publisher |
| Code | src/launch1_publisher.cpp |
| Launch File | launch/launch1.launch |
A publisher made for the purpose of Launch1 file. Simply publishes messages to the topic ~/pub_topic. Also uses a local parameter called l1pub_PubFreq to set the frequency of publishing (see code for more information).
To build this node, insert the following lines at the appropriate places in the CMakeLists.txt file of the package
add_executable(launch1_publisher src/launch1_publisher.cpp)
target_link_libraries(launch1_publisher ${catkin_LIBRARIES})Run catkin_make in the workspace folder to build the node. This node, along with some others, is supposed to be run in the launch1.launch process (check it out here).
| Field | Value |
|---|---|
| Node name | launch1_subscriber |
| Code | src/launch1_subscriber.cpp |
| Launch File | launch/launch1.launch |
A subscriber made for the purpose of Launch1 file. Simply subscribes to messages on topic ~/subs_topic (see code for more information).
To build this node, insert the following lines at the appropriate places in the CMakeLists.txt file of the package
add_executable(launch1_subscriber src/launch1_subscriber.cpp)
target_link_libraries(launch1_subscriber ${catkin_LIBRARIES})Run catkin_make in the workspace folder to build the node. This node, along with some others, is supposed to be run in the launch1.launch process (check it out here).
| Field | Value |
|---|---|
| Name | launch1_params |
| File | src/launch1_parameters.cpp |
| Launch File | launch/launch1.launch |
A node made to print out all parameter keys. It is suggested that you see l1_params1 and l1_params2 .yaml parameter files.
To build this node, insert the following lines at the appropriate places in the CMakeLists.txt file of the package
add_executable(launch1_parameters src/launch1_parameters.cpp)
target_link_libraries(launch1_parameters ${catkin_LIBRARIES})Run catkin_make in the workspace folder to build the node. This node, along with some others, is supposed to be run in the launch1.launch process (check it out here).
| Field | Value |
|---|---|
| Name | simple_cpp_firstdr_server |
| File | src/simple_FirstDR_server.cpp |
| Dynamic Reconfiguration File | cfg/FirstDR.cfg |
A dynamic reconfiguration server made to host the parameters included in the .cfg file. This node depends on the dynamic reconfiguration file. A server maintains the record of parameters and provides a callback interface for handling updates (these updates are made by a client).
To build this node, add the following to CMakeLists.txt file
add_executable(simple_cpp_firstdr_server src/simple_FirstDR_server.cpp)
add_dependencies(simple_cpp_firstdr_server ${PROJECT_NAME}_gencfg)
target_link_libraries(simple_cpp_firstdr_server ${catkin_LIBRARIES})Notice the add_dependencies function, it is needed for the .cfg files to generate headers before building this node (because of dependency).
Run catkin_make in the workspace folder to build the node.
First, run roscore, then run this node using
rosrun cpp_basic_nodes simple_cpp_firstdr_serverThe output will consist of the default parameters being loaded in the callback (with level being 0xffff ffff, which is 4294967295). The node then goes into spinning mode.
To call the callback, you'll need a client. You could create a node for that, however a simple GUI client is available using rqt_reconfigure. To run it, run
rosrun rqt_reconfigure rqt_reconfigureThis should open a GUI window like whats shown below
You can modify the values and see the output in the terminal running the node. You can also save the modified parameters as a .yaml file and restore them. This shall also allow testing how multiple parameters can be changed in just one attempt.
For example, for the following rqt_reconfigure configurations
The result is the following
Notice the level passed, it is the binary OR of all the parameters with a different value. You may also verify that the parameters are actual parameters on the ROS Parameter Server by inspecting the output of rosparam list. You may also what to check the /simple_cpp_firstdr_server/set_parameters service.
| Field | Value |
|---|---|
| Name | simple_cpp_firstdr_client |
| File | src/simple_FirstDR_client.cpp |
| Dynamic Reconfiguration File | cfg/FirstDR.cfg |
A dynamic reconfiguration client made to modify parameters on a dynamic reconfiguration server. The parameters are included in the specified .cfg dynamic reconfiguration file. A client sends commands to the server (which maintains a service to handle changes in parameters). A simple server is implemented in this package.
To build this node, add the following to CMakeLists.txt file
add_executable(simple_cpp_firstdr_client src/simple_FirstDR_client.cpp)
add_dependencies(simple_cpp_firstdr_client ${PROJECT_NAME}_gencfg)
target_link_libraries(simple_cpp_firstdr_client ${catkin_LIBRARIES})Run catkin_make in the workspace folder to build the node.
First, run roscore. Before running this node, you need the simple_cpp_firstdr_server node running (because it serves as the server for this node, check the code). To run it, use this command
rosrun cpp_basic_nodes simple_cpp_firstdr_serverThen, run this node using
rosrun cpp_basic_nodes simple_cpp_firstdr_clientThe output on this node screen may be the following
The output on the server node may be the following
You may check the service /simple_cpp_firstdr_server/set_parameters and may also see the output of rosrun rqt_graph rqt_graph. What may be more interesting is that running rosrun rqt_reconfigure rqt_reconfigure opens the same GUI window as it did earlier in the case of server, but it also shows the updates in parameters in real time. This synchronization is handled in the background by the dynamic_reconfigure package.
| Field | Value |
|---|---|
| Name | simple_library_node |
| File | src/simple_library_node.cpp |
| Library | simple_library library |
A node made to demonstrate how to use a simple library of another package, here the library is simple_library in basic_cpp_libs package. You might want to explore the library and its building procedures first (before proceeding here).
Add the dependency on basic_cpp_libs by
- Add the
<depend>basic_cpp_libs</depend>line in thepackage.xml - Add
basic_cpp_libsto the list of packages infind_package(catkin REQUIRED COMPONENTS ...)function in theCMakeLists.txtfile
To install this node, add the following in the CMakeLists.txt at the appropriate places
add_executable(cpp_simple_library_node src/simple_library_node.cpp)
target_link_libraries(cpp_simple_library_node ${catkin_LIBRARIES})To run this node, first run roscore and then run
rosrun cpp_basic_nodes cpp_simple_library_node| Field | Value |
|---|---|
| Name | basic_math_node |
| File | src/basic_math_node.cpp |
| Library | basic_math library |
A node made to demonstrate how to use a relative complex library from another package, here the library is basic_math from basic_cpp_libs package. You might want to explore the library and its building procedures first (before proceeding here).
Add the dependency on basic_cpp_libs by
- Add the
<depend>basic_cpp_libs</depend>line in thepackage.xml - Add
basic_cpp_libsto the list of packages infind_package(catkin REQUIRED COMPONENTS ...)function in theCMakeLists.txtfile
To install this node, add the following in the CMakeLists.txt at the appropriate places
add_executable(cpp_basic_math_node src/basic_math_node.cpp)
target_link_libraries(cpp_basic_math_node ${catkin_LIBRARIES})To run this node, first run roscore and the run
rosrun cpp_basic_nodes cpp_basic_math_nodeServices declared in this package
| Field | Value |
|---|---|
| Name | AddAllFloat64Numbers_cpp |
| File | srv/AddAllFloat64Numbers_cpp.srv |
| Service Request | float64[] data |
| Service Response | float64 sum |
A service that adds all the numbers sent in the request and sends the result as a response. For example, if we send 1, -2.3, 56, -4 in request, it will send 50.7 (their sum) in response. However, note that the logic is not in the .srv file, but in the service server. This file only describes the structure.
The file is actually just a service description file. We need to build the files (header and source files) so that this and other packages can use this service.
To do that, open package.xml file and add the following lines at appropriate places:
-
Add a
build_dependtomessage_generation. This will allow building messages, services and actions at compile time.Go to the part where
<build_depend>tags are located and add the following tags to the list<build_depend>message_generation</build_depend> <build_depend>std_msgs</build_depend>
This would tell that the package depends on
message_generationpackage for building. The packagemessage_generationis used for building the messages, services and actions. The second package,std_msgs, is needed for the messages. -
Add an
exec_dependtomessage_runtime.Go to the part where
<exec_depend>tags are located and add the following tag to the list<exec_depend>message_runtime</exec_depend> <exec_depend>std_msgs</exec_depend>
This is used to tell that we need the
message_runtimepackage at runtime. The second package,std_msgs, is needed for the messages.
As the package.xml file is just a manifesto file, we need to make the following changes to the CMakeLists.txt file (as that is the file which is used to actually build the package)
-
In the
find_packagefunction, addmessage_generationtocatkin REQUIRED COMPONENTSin a new line (after the end of already declared packages)After adding
message_generation(and addingstd_msgsfor standard messages), the function must look somewhat like thisfind_package(catkin REQUIRED COMPONENTS roscpp message_generation std_msgs )
More about the
find_packagefunction here -
Under
catkin specific configurationheading (just before theBuildheading), addmessage_runtimeasCATKIN_DEPENDS.After adding
message_runtime(andstd_msgsfor standard messages), the function must look somewhat like thiscatkin_package( # INCLUDE_DIRS include # LIBRARIES cpp_basic_nodes CATKIN_DEPENDS roscpp message_runtime std_msgs # DEPENDS system_lib )
More about the
catkin_packagefunction here -
Go to the
Declare ROS messages, services and actionsheading. You shall also find the whole procedure as comments in this section.-
Add the
add_action_files(you could uncomment the existing code, or write a new one under it).Include the
.srvfiles declared in thesrvfolder here. After adding the function, it would look like thisadd_service_files( FILES AddAllFloat64Numbers_cpp.srv ) -
Add the
generate_messagesfunction to the macro. This is to invoke code generation for the source code.Add the
std_msgsdependency. After everything, the function must look like thisgenerate_messages( DEPENDENCIES std_msgs # Float64 )
There is an example on roswiki to demonstrate changes to the CMakeLists.txt file for adding custom messages, services and actions
-
After all this, run the catkin_make command in the workspace directory. You must see the header files for C++ nodes in the devel/include/cpp_basic_nodes directory of the workspace. The main header file, request file and response file are present here. Everything is stored in a namespace bearing the same name as the package name (that is cpp_basic_nodes).
For python, the library source files are present in the devel/lib/python3/dist-packages/cpp_basic_nodes directory (inside the workspace directory).
For any IDE, you may want to include the devel/include directory (for auto completion features).
Actions declared in this package
| Field | Value |
|---|---|
| Name | CountNumbers_cpp |
| File | action/CountNumbers_cpp.action |
| Goal | uint32 target_number; uint32 del_ms |
| Result | string res_note |
| Feedback | uint32 curr_number |
An action that counts the numbers up to a requested number. For example, if the goal is to count up to 5 (target_number) with a delay of 1000 (del_ms), then in feedback, the node will send numbers 1, 2, 3, 4, 5 and then send the result as Done (or something similar). Note that the .action file only describes the structure of the action. The logic is defined in the action server implementation and not in the .action file.
The file is actually just an action description file. We need to build the files (header and source files) so that this and other packages can use this service. Its suggested that you see the building process of services first.
To do that, open package.xml file and add the following lines at appropriate places:
-
Add a
dependtoactionlibandactionlib_msgs. This will allow us to build the actions.Add these lines before the
exectags (just a convention)<depend>actionlib</depend> <depend>actionlib_msgs</depend>
This would tell that the package depends on
actionlibandactionlib_msgsduring build and execution times.
Add the following at appropriate places
-
In the
find_packagefunction, addactionlib,genmsgandactionlib_msgstocatkin REQUIRED COMPONENTSin a new line (after the end of already declared packages)The function must look somewhat like this
find_package(catkin REQUIRED COMPONENTS roscpp message_generation std_msgs actionlib genmsg actionlib_msgs )The
genmsgpackage is to generate messages out of the.actionfile. Messages are generated for Goal, Result and Feedback. Packagemessage_generationis not required (it is from the services section). -
Go to the
Declare ROS messages, services and actionsheading.-
Add the
add_action_filesfunctionInclude the
.actionfiles declared in theactionfolder here. After adding the function, it would look like thisadd_action_files( FILES CountNumbers_cpp.action ) -
Add the
generate_messagesfunction.Add the
actionlib_msgsdependency. After everything, the function must look like thisgenerate_messages( DEPENDENCIES std_msgs # Float64 actionlib_msgs )The
std_msgsis not necessary (it is for the services in the package). -
Add
actionlib_msgsto thecatkin_packagefunction as aCATKIN_DEPENDSpackageAfter adding it, the function may look somewhat like this
catkin_package( # INCLUDE_DIRS include # LIBRARIES cpp_basic_nodes CATKIN_DEPENDS roscpp message_runtime std_msgs actionlib_msgs # DEPENDS system_lib )
The
std_msgsis not necessary (it is for the services in the package).
There is an example on roswiki to demonstrate a sample
.actionfile and building it. -
After all that, run catkin_make in the ros workspace directory. After a successful build, the header files for C++ nodes must be available in devel/include/cpp_basic_nodes directory of the workspace (python libraries are in the devel/lib/python3/dist-packages/cpp_basic_nodes directory). You can see the messages created by running the command
rosmsg list | grep cpp_basic_nodes/CountNumbers_cppThere will be messages for actions as well as individual messages for the goal, feedback and result.
| Field | Value |
|---|---|
| Name | Params1 |
| File | yaml/Params1.yaml |
This file contains parameters that can be loaded to the ROS Master (on the Parameter Server).
Make sure the master is running first
roscoreWe use the rosparam tool to list, get and load parameters from a YAML file. Now let's list the parameters that are present when roscore is launched.
rosparam listSay we want to get the value of /run_id, use rosparam get
rosparam get /run_idYou can save all the current parameters in a temporary file
rosparam dump curr_params.yamlThe contents of the file are the parameters in the ROS Parameter Server. To load the parameters in this file (Params1.yaml) into the ROS parameter server, run the following command
rosparam load `rospack find cpp_basic_nodes`/yaml/Params1.yamlThe rospack find cpp_basic_nodes command is to find this package (named cpp_basic_nodes), and then point to the YAML file from which parameters have to be loaded. You can view individual parameters using rosparam get or dump it into another file.
| Field | Value |
|---|---|
| Name | l1_params1 |
| File | yaml/l1_params1.yaml |
This file is to load some parameters for launch1. Note that the cat command is used to pipe the contents to the <param> in the launch file.
| Field | Value |
|---|---|
| Name | l1_params2 |
| File | yaml/l1_params2.yaml |
This file is to load some parameters for launch1. This file contains parameters intended for global scope / usage. Note that the cat command is used to pipe the contents to the <param> in the launch file.
| Field | Value |
|---|---|
| Name | launch1 |
| File | launch/launch1.launch |
A launch file is used to execute multiple nodes and run multiple commands in one go, so that you do not have to keep opening new terminals and typing new commands every time. Check out the file to know more.
In order to run this file, use the following command
roslaunch cpp_basic_nodes launch1.launchAfter launching, the following nodes must have spawned (use rosnode list to get these):
/rqt_console: This is a console to visualize the messages being transmitted (since the output is logged, although there also is provision to log to the screen but it is less preferred as it would produce too much clutter)./l1/ps/cppl1_publisher: This is the publisher node (note the namespace and renaming)./l1/ps/cppl1_subscriber: This is the subscriber node./l1/params/cppl1_parameters: This is the parameter keys node.
The following topics are of importance (use rostopic list to get these):
/l1/ps/topic: The topic to which the publisher publishes and subscriber subscribes. Note that this is completely achieved through argument remapping and namespace allocation (because the nodes themselves use a different topic by default).
You must observe the parameters present by running rosparam list. The following are important observations:
/global/*are parameters in the global declaration/l1/params/set1/*are parameters in the group declaration/l1/ps/cppl1_publisher/l1pub_PubFreqis a private parameter but still shared with the parameter server
Also note that upon closing the rqt_console window, the launch closes. This is because of the required attribute in the <node> for it.
After closing the launch, it is possible to see all the output generated by the nodes. This is available in the directory ~/.ros/log/latest (by default). Each file will contain the output generated by the particular node.
About: Dynamic Reconfiguration is used to create parameters that can be updated at runtime. This is done using a client and server model (very similar to that of services), but here the server hosts and stores the parameters and the client is used to modify them. A
.cfgfile outlines the details about the parameter (kind of like how.msgfiles define a message, or.srvfiles define a service).
Dynamic Reconfiguration Files in this package
| Field | Value |
|---|---|
| Name | FirstDR |
| File | cfg/FirstDR.cfg |
Holds the following dynamic reconfigurations as template
| Parameter Name | Type | Description | Default Value |
|---|---|---|---|
| user_int | int_t |
A configurable integer | 50 |
| usr_int1 | int_t |
An integer with level 3 | 50 |
| usr_int2 | int_t |
An integer with level 2 | 50 |
| usr_int3 | int_t |
An integer with level 8 | 50 |
| user_bool | bool_t |
A boolean value | False |
| user_str | str_t |
A string value | "Hello, World!" |
To build a dynamic reconfiguration file, you have to first add dependency to a package called dynamic_reconfigure. This package contains all code to build the files.
-
Add the following lines to
Package.xmlfile at the appropriate placesYou will need build time and run time dependency on
dynamic_reconfigure<build_depend>dynamic_reconfigure</build_depend> <exec_depend>dynamic_reconfigure</exec_depend>
-
Open
CMakeLists.txtand adddynamic_reconfigureto the list of packages in thefind_package(catkin REQUIRED COMPONENTS ...)function. -
You have to now define the particular
.cfgfiles in your package. There is a section inCMakeLists.txtfile to define those. Scroll down to a section labelledDeclare ROS dynamic reconfigure parameters.Add the function
generate_dynamic_reconfigure_optionsto the file (either uncomment or add below).generate_dynamic_reconfigure_options( cfg/FirstDR.cfg )The parameter passed (
cfg/FirstDR.cfghere) is the path of the.cfgfile in the package. Usually, these files are stored in a folder namedcfg(just as there are dedicated folders for service files, calledsrv).
After this, run catkin_make in the workspace directory. Wait till build is completed.
Go to the directory devel/include/cpp_basic_nodes where you'll find the .h files generated for the file (here, it will be FirstDRConfig.h file). If you're interested in headers for python, they're stored in devel/lib/python3/dist-packages/cpp_basic_nodes/cfg directory in the workspace.
- roswiki







