In the post, you will learn how to create a C++ subscriber to a custom msg array published with Python publisher. This answers the following question on the ROS Answers forum: https://answers.ros.org/question/324325/how-to-use-c-subscribe-to-a-custom-msg-array-published-by-python/.
What you will learn
- How to create a custom message
- How to create a ROS Publisher with Python
- How to create a ROS Subscriber with C++
On your marks…get set…let’s go!
Related Resources
- ROS Development Studio (ROSDS)
- Robot Ignite Academy
- ROS Basics Course (Python)
- ROS Basics Course (C++)
Step 0: Get your development environment ready
Either of the following will do:
- Use the ROS Development Studio (ROSDS), an online platform for developing for ROS within a PC browser. Easy-peasy. I’m using this option for this post.
- Once you log in, click on the New ROSject button to create a project that will host your code. Then Click on Open ROSject to launch the development/simulation environment.
- To open a “terminal” on ROSDS, pick the
Shell
app from the Tools menu. - You can find the
IDE
app on the Tools menu.
- You have ROS installed on a local PC. Okay, skip to Step 2.
Next step!
Step 1: Create the custom messages
Err, not so fast! We need to create a package first. So, open a terminate, browse to your catkin workspace source directory and create the package and some of the files we will need for the custom messages. Note that when creating the package, we added both rospy
and roscpp
because we will be working with C++ and Python source codes.
cd ~/catkin_ws/src catkin_create_pkg cpp_python roscpp rospy cd cpp_python mkdir -p msg touch InfoData.msg touch InfoDataArray.msg
Now open the IDE and locate the open both message files in the msg
subdirectory of the package. In InfoData.msg
, paste in the following:
int32 num string color string name
Put this in InfoDataArray.msg
:
InfoData[] infos
Add the following lines to your CMakeLists.txt
and package.xml
in order to recognize the custom messages:
CMakeLists.txt
:
1. Find the existing add_message_files
directive, uncomment it, and change it to the following:
add_message_files( FILES InfoData.msg InfoDataArray.msg )
2. Find the generate_messages
directive and uncomment it:
generate_messages( DEPENDENCIES std_msgs # Or other packages containing msgs )
3. Find the catkin_package
directive and uncomment the CATKIN_DEPENDS
line:
catkin_package( # INCLUDE_DIRS include # LIBRARIES cpp_python CATKIN_DEPENDS roscpp rospy # DEPENDS system_lib )
Of course, please save the file!
package.xml
:
Add the following lines required to generate the custom messages:
<build_depend>message_generation</build_depend> <build_export_depend>message_generation</build_export_depend> <exec_depend>message_runtime</exec_depend>
Save!
Compile the messages:
# make sure you run this from the root of your catkin workspace (e.g catkin_ws) catkin_make
Source the workspace:
# make sure you run this from the root of your catkin workspace (e.g catkin_ws) source devel/setup.bash
Step 2: Create the Python publisher node
Create a python file in the src folder and make it executable
roscd cpp_python cd src touch infodata_publisher.py chmod +x infodata_publisher.py
Using the IDE, paste in the following code
#! /usr/bin/env python import rospy # import the ros Python api from cpp_python.msg import InfoData, InfoDataArray # import the custom messages rospy.init_node('infodata_publisher_node') # create a node to run the publisher pub = rospy.Publisher('/infodata', InfoDataArray, queue_size=1) # create the publisher rate = rospy.Rate(1) # create a rate (per second) for publishing infodata = InfoData() # create the infodata message infodata_array = InfoDataArray() # create the infodata array # set the variables of the info data message infodata.num = 5 infodata.color = 'red' infodata.name = 'data1' # push several infodata messages into the info data array for x in range(10): infodata_array.infos.append(infodata) # continously publish the infodata array at the rate specified # until someone stops the node while not rospy.is_shutdown(): pub.publish(infodata_array.infos) rate.sleep()
Step 3: Create the C++ subscriber node
Create a C++ file in the src folder
roscd cpp_python cd src touch infodata_subscriber.cpp
Locate the file in the IDE and paste in the following code:
// Import the infodata messaages #include <cpp_python/InfoData.h> #include <cpp_python/InfoDataArray.h> #include <ros/ros.h> // import the ros C++ api // the function that takes the message from the subscriber and does // something with it void infodataCallback(const cpp_python::InfoDataArray::ConstPtr &msg) { ROS_INFO("%d", msg->infos[0].num); ROS_INFO("%s", msg->infos[0].color.c_str()); ROS_INFO("%s", msg->infos[0].name.c_str()); } int main(int argc, char **argv) { // create a node for running the subscriber ros::init(argc, argv, "infodata_subscriber_node"); ros::NodeHandle nh; // create the subscriber ros::Subscriber sub = nh.subscribe("/infodata", 1000, infodataCallback); // Run the subscriber until someone stops the program with Ctrl + C ros::spin(); return 0; }
Add the following lines to CMakeLists.txt
, under the Build
section, so the C++ can be compiled:
add_executable(infodata_subscriber src/infodata_subscriber.cpp) add_dependencies(infodata_subscriber ${cpp_python_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) target_link_libraries(infodata_subscriber ${catkin_LIBRARIES} )
Compile the C++ node:
# make sure you run this from the root of your catkin workspace (e.g catkin_ws) catkin_make
Step 4: Run the Python publisher node
# make sure you run this from the root of your catkin workspace (e.g catkin_ws) source devel/setup.bash nohup roscore & rosrun cpp_python infodata_publisher.py
Nothing is happening? Nah, wait until we launch the subscriber! So, then, let’s do it!
Step 5: Run the C++ subscriber node
Open another terminal and run:
user:~$ cd catkin_ws/ user:~/catkin_ws$ source devel/setup.bash user:~/catkin_ws$ rosrun cpp_python infodata_subscriber [ INFO] [1583243129.975478016]: 5 [ INFO] [1583243129.975588039]: red [ INFO] [1583243129.975620409]: data1 [ INFO] [1583243130.975436776]: 5 [ INFO] [1583243130.975521758]: red [ INFO] [1583243130.975555258]: data1 [ INFO] [1583243131.975349645]: 5 # ...
So that was it! That’s how to create a C++ subscriber for a Python publisher node.
Extra: Video of this post
We made a video showing how we solved this challenge. If you prefer “sights and sounds” to “black and white”, here you go:
Feedback
Did you like this post? Do you have any questions about the explanations? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.
If you want to learn about other ROS or ROS2 topics, please let us know in the comments area and we will do a video or post about it.
Edited by Bayode Aderinola
Want to play with the complete code right away? You can get a copy of the ROSject at the link below (requires an account on ROSDS).
I cant read this code, there is literally no syntax highlighting