ROS C++ Practice - Message
ROS Publisher and Subscriber Nodes Using C++
Step 1: Set Up Your ROS Workspace - Before you create nodes, make sure you have a ROS workspace set up. If you don’t have one, you can create it using the following commands:
mkdir -p ~/catkin_ws/src cd ~/catkin_ws/ catkin_make
Step 2: Create a ROS Package
Inside the src directory of your ROS workspace, create a new ROS package. Replace ros_tutorials_topic with your desired package name:
cd ~/catkin_ws/src catkin_create_pkg ros_tutorials_topic roscpp std_msgs
Step 3: Create the Publisher Node
Navigate to your package directory:
cd ~/catkin_ws/src/ros_tutorials_topic/src
Create a source file for the publisher node. For example, topic_publisher.cpp:
#include "ros/ros.h" // ROS Default Header File #include "ros_tutorials_topic/MsgTutorial.h" // MsgTutorial Message File Header. The header file is automatically created when building the package. int main(int argc, char **argv) // Node Main Function { ros::init(argc, argv, "topic_publisher"); // Initializes Node Name ros::NodeHandle nh; // Node handle declaration for communication with ROS system // Declare publisher, create publisher 'ros_tutorial_pub' using the 'MsgTutorial' // message file from the 'ros_tutorials_topic' package. The topic name is // 'ros_tutorial_msg' and the size of the publisher queue is set to 100. ros::Publisher ros_tutorial_pub = nh.advertise<ros_tutorials_topic::MsgTutorial>("ros_tutorial_msg", 100); // Set the loop period. '10' refers to 10 Hz and the main loop repeats at 0.1 second intervals ros::Rate loop_rate(10); ros_tutorials_topic::MsgTutorial msg; // Declares message 'msg' in 'MsgTutorial' message file format int count = 0; // Variable to be used in message while (ros::ok()) { msg.stamp = ros::Time::now(); // Save current time in the stamp of 'msg' msg.data = count; // Save the the 'count' value in the data of 'msg' ROS_INFO("send msg = %d", msg.stamp.sec); // Prints the 'stamp.sec' message ROS_INFO("send msg = %d", msg.stamp.nsec); // Prints the 'stamp.nsec' message ROS_INFO("send msg = %d", msg.data); // Prints the 'data' message ros_tutorial_pub.publish(msg); // Publishes 'msg' message loop_rate.sleep(); // Goes to sleep according to the loop rate defined above. ++count; // Increase count variable by one } return 0; }
Step 4: Create the Subscriber Node
Create another source file for the subscriber node. For example, topic_subscriber.cpp:
#include "ros/ros.h" // ROS Default Header File #include "ros_tutorials_topic/MsgTutorial.h" // MsgTutorial Message File Header. The header file is automatically created when building the package. // Message callback function. This function is called when a message is received on the topic // named 'ros_tutorial_msg'. It takes a 'MsgTutorial' message from the 'ros_tutorials_topic' package as input. void msgCallback(const ros_tutorials_topic::MsgTutorial::ConstPtr& msg) { ROS_INFO("Received msg = %d", msg->stamp.sec); // Print the 'stamp.sec' message ROS_INFO("Received msg = %d", msg->stamp.nsec); // Print the 'stamp.nsec' message ROS_INFO("Received msg = %d", msg->data); // Print the 'data' message } int main(int argc, char **argv) // Node Main Function { ros::init(argc, argv, "topic_subscriber"); // Initialize the node with the name "topic_subscriber" ros::NodeHandle nh; // Node handle declaration for communication with the ROS system // Declare a subscriber named 'ros_tutorial_sub' using the 'MsgTutorial' // message format from the 'ros_tutorials_topic' package. The topic name is // 'ros_tutorial_msg', and the size of the subscriber queue is set to 100. ros::Subscriber ros_tutorial_sub = nh.subscribe("ros_tutorial_msg", 100, msgCallback); // A function that enters a loop, waits for messages to be received, // and executes the callback function when a message is received. ros::spin(); return 0; }
Step 5: Update CMakeLists.txt
Make the CMakeLists.txt file in your package directory (ros_tutorials_topic) and add the following lines to configure the build for both the publisher and subscriber nodes:
cmake_minimum_required(VERSION 2.8.3) project(ros_tutorials_topic) find_package(catkin REQUIRED COMPONENTS roscpp std_msgs) catkin_package( LIBRARIES ros_tutorials_topic CATKIN_DEPENDS std_msgs roscpp ) include_directories(${catkin_INCLUDE_DIRS}) add_executable(topic_publisher src/topic_publisher.cpp) add_dependencies(topic_publisher ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) target_link_libraries(topic_publisher ${catkin_LIBRARIES}) add_executable(topic_subscriber src/topic_subscriber.cpp) add_dependencies(topic_subscriber ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) target_link_libraries(topic_subscriber ${catkin_LIBRARIES})
Step 6: Create the launch File
Create a union_msg.launch file for nodes:
mkdir -p ~/catkin_ws/src/launch cd ~/catkin_ws/src/launch touch union_msg.launch
<launch> <node pkg="ros_tutorials_topic" type="topic_publisher" name="topic_publisher"/> <node pkg="ros_tutorials_topic" type="topic_subscriber" name="topic_subscriber"/> </launch>
Step 7: Build and Run
Build your package using catkin_make:
cd ~/catkin_ws catkin_make
Source the setup script:
source devel/setup.bash
Now you can run the publisher and subscriber nodes in separate terminal windows:
Terminal 1 (for the publisher node):
rosrun ros_tutorials_topic topic_publisher
Terminal 2 (for the subscriber node):
rosrun ros_tutorials_topic topic_subscriber
Or, you can run the publisher and subscriber at once using a launch file.
roslaunch ros_tutorials_topic union_msg.launch
You should see the subscriber printing the messages published by the publisher.