Talker & Listener (Optional)
This tutorial serves as an additional exercise for students to learn the very fundamental and important functions (see section 0.1 Objectives) of ROS using "Talker & Listener" as example. While the CG2111A module does not require you to fully understand these methodologies, gaining knowledge in these areas can be immensely beneficial for your future modules that utilize ROS, or even in your career.
It's important to note that in CG2111A, the teaching team will handle these functions for you. Therefore, if you're not interested in the details behind some commands, you may choose to skip this entire tutorial. This flexibility allows you to focus on the aspects of ROS that are most relevant and interesting to you.
Each step in this tutorial is crucial, with later steps building upon the successful completion of earlier ones. Therefore, after finishing each step, please make sure to check the corresponding checkbox in this tutorial. This action will change the status from "Waiting Completion" to "Marked as Completed." This simple practice ensures you're progressing correctly through the material and helps prevent any oversight that could impact later stages.
0. Introduction
In this exercise, students will develop two nodes within the ROS framework: one node will publish a value, and another node will echo the published value. Communication between nodes in ROS is facilitated through topics, akin to channels in which messages are broadcasted and received. To understand this concept, consider the following analogy:
- Imagine Tom and Jerry, representing two nodes in a network. Tom wishes to send information to Jerry using two different methods: email and telegram, analogous to two separate topics in ROS.
- In this scenario, Tom acts as a publisher who sends information, while Jerry acts as a subscriber who receives it. For Jerry to receive the information sent via email, he must have an email account—similarly, a node must subscribe to a topic to receive messages broadcasted on that topic.
- The information relayed through these topics is referred to as a message. For instance, a message could be "I saw 3 students in location 1". If the information pattern repeats with slight variations (e.g., "I saw 4 students in location 2"), the messages can be simplified to just the varying elements, like "3 and 1" followed by "4 and 2".
- The structure and meaning of these messages are defined in a
.msg
file, a text file that describes the fields of a message, effectively outlining the data structure contained within a topic.
In this project, your workspace should be named cg2111a_exercise_ws
, and your package should be cg2111a_talker_listener
.
0.1 Objectives
By the end of this project, students should be able to:
- Create a workspace and a package.
- Develop nodes and define messages.
- Utilize nodes and messages to facilitate one-way communication.
- Design and implement a launch file.
For your reference, the following tree structure represents the organization of files and directories within the cg2111a_exercise_ws
ROS workspace. This includes the ROS package cg2111a_talker_listener
, along with its nodes, launch file, and configuration files.
cg2111a_exercise_ws/
├── build/
├── devel/
│ ├── ...
│ └── setup.bash
├── src/
│ └── cg2111a_talker_listener/
│ ├── CMakeLists.txt (modified to include talker and listener executables)
│ ├── package.xml (modified to include necessary dependencies)
│ ├── launch/
│ │ └── cg2111a_talker_listener.launch (launch file for starting talker and listener nodes)
│ └── src/
│ ├── talker.cpp (publisher node source code)
│ └── listener.cpp (subscriber node source code)
└── (other ROS workspace directories and files)
Click here to expand the whole file tree.
~/cg2111a_exercise_ws $ tree
.
├── build
│ ├── atomic_configure
│ │ ├── env.sh
│ │ ├── local_setup.bash
│ │ ├── local_setup.sh
│ │ ├── local_setup.zsh
│ │ ├── setup.bash
│ │ ├── setup.sh
│ │ ├── _setup_util.py
│ │ └── setup.zsh
│ ├── catkin
│ │ └── catkin_generated
│ │ └── version
│ │ └── package.cmake
│ ├── catkin_generated
│ │ ├── env_cached.sh
│ │ ├── generate_cached_setup.py
│ │ ├── installspace
│ │ │ ├── env.sh
│ │ │ ├── local_setup.bash
│ │ │ ├── local_setup.sh
│ │ │ ├── local_setup.zsh
│ │ │ ├── setup.bash
│ │ │ ├── setup.sh
│ │ │ ├── _setup_util.py
│ │ │ └── setup.zsh
│ │ ├── order_packages.cmake
│ │ ├── order_packages.py
│ │ ├── setup_cached.sh
│ │ └── stamps
│ │ └── Project
│ │ ├── interrogate_setup_dot_py.py.stamp
│ │ ├── order_packages.cmake.em.stamp
│ │ ├── package.xml.stamp
│ │ └── _setup_util.py.stamp
│ ├── CATKIN_IGNORE
│ ├── catkin_make.cache
│ ├── cg2111a_talker_listener
│ │ ├── catkin_generated
│ │ │ ├── cg2111a_talker_listener-msg-extras.cmake.develspace.in
│ │ │ ├── cg2111a_talker_listener-msg-extras.cmake.installspace.in
│ │ │ ├── installspace
│ │ │ │ ├── cg2111a_talker_listenerConfig.cmake
│ │ │ │ ├── cg2111a_talker_listenerConfig-version.cmake
│ │ │ │ ├── cg2111a_talker_listener-msg-extras.cmake
│ │ │ │ ├── cg2111a_talker_listener-msg-paths.cmake
│ │ │ │ └── cg2111a_talker_listener.pc
│ │ │ ├── ordered_paths.cmake
│ │ │ ├── package.cmake
│ │ │ ├── pkg.develspace.context.pc.py
│ │ │ ├── pkg.installspace.context.pc.py
│ │ │ └── stamps
│ │ │ └── cg2111a_talker_listener
│ │ │ ├── package.xml.stamp
│ │ │ ├── pkg-genmsg.cmake.em.stamp
│ │ │ └── pkg.pc.em.stamp
│ │ ├── cmake
│ │ │ ├── cg2111a_talker_listener-genmsg.cmake
│ │ │ └── cg2111a_talker_listener-genmsg-context.py
│ │ ├── CMakeFiles
│ │ │ ├── cg2111a_talker_listener_gencpp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_generate_messages_cpp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_generate_messages.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_generate_messages_eus.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_generate_messages_lisp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_generate_messages_nodejs.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_generate_messages_py.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_geneus.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_genlisp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_gennodejs.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── cg2111a_talker_listener_genpy.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ ├── listener.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── CXX.includecache
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ ├── flags.make
│ │ │ │ ├── link.txt
│ │ │ │ ├── progress.make
│ │ │ │ └── src
│ │ │ │ └── listener.cpp.o
│ │ │ ├── progress.marks
│ │ │ ├── roscpp_generate_messages_cpp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── roscpp_generate_messages_eus.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── roscpp_generate_messages_lisp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── roscpp_generate_messages_nodejs.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── roscpp_generate_messages_py.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── rosgraph_msgs_generate_messages_cpp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── rosgraph_msgs_generate_messages_eus.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── rosgraph_msgs_generate_messages_lisp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── rosgraph_msgs_generate_messages_nodejs.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── rosgraph_msgs_generate_messages_py.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ └── progress.make
│ │ │ ├── std_msgs_generate_messages_cpp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── std_msgs_generate_messages_eus.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── std_msgs_generate_messages_lisp.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── std_msgs_generate_messages_nodejs.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ ├── std_msgs_generate_messages_py.dir
│ │ │ │ ├── build.make
│ │ │ │ ├── cmake_clean.cmake
│ │ │ │ ├── DependInfo.cmake
│ │ │ │ ├── depend.internal
│ │ │ │ ├── depend.make
│ │ │ │ └── progress.make
│ │ │ └── talker.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── CXX.includecache
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── progress.make
│ │ │ └── src
│ │ │ └── talker.cpp.o
│ │ ├── cmake_install.cmake
│ │ ├── CTestTestfile.cmake
│ │ └── Makefile
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.16.3
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ ├── CMakeCCompilerId.c
│ │ │ │ └── tmp
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ ├── CMakeCXXCompilerId.cpp
│ │ │ └── tmp
│ │ ├── clean_test_results.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── DependInfo.cmake
│ │ │ └── progress.make
│ │ ├── cmake.check_cache
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeError.log
│ │ ├── CMakeOutput.log
│ │ ├── CMakeRuleHashes.txt
│ │ ├── CMakeTmp
│ │ ├── download_extra_data.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── DependInfo.cmake
│ │ │ └── progress.make
│ │ ├── doxygen.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── DependInfo.cmake
│ │ │ └── progress.make
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ ├── run_tests.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── DependInfo.cmake
│ │ │ └── progress.make
│ │ ├── TargetDirectories.txt
│ │ └── tests.dir
│ │ ├── build.make
│ │ ├── cmake_clean.cmake
│ │ ├── DependInfo.cmake
│ │ └── progress.make
│ ├── cmake_install.cmake
│ ├── CTestConfiguration.ini
│ ├── CTestCustom.cmake
│ ├── CTestTestfile.cmake
│ ├── gtest
│ │ ├── CMakeFiles
│ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ └── progress.marks
│ │ ├── cmake_install.cmake
│ │ ├── CTestTestfile.cmake
│ │ ├── googlemock
│ │ │ ├── CMakeFiles
│ │ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ │ ├── gmock.dir
│ │ │ │ │ ├── build.make
│ │ │ │ │ ├── cmake_clean.cmake
│ │ │ │ │ ├── DependInfo.cmake
│ │ │ │ │ ├── depend.make
│ │ │ │ │ ├── flags.make
│ │ │ │ │ ├── link.txt
│ │ │ │ │ ├── progress.make
│ │ │ │ │ └── src
│ │ │ │ ├── gmock_main.dir
│ │ │ │ │ ├── build.make
│ │ │ │ │ ├── cmake_clean.cmake
│ │ │ │ │ ├── DependInfo.cmake
│ │ │ │ │ ├── depend.make
│ │ │ │ │ ├── flags.make
│ │ │ │ │ ├── link.txt
│ │ │ │ │ ├── progress.make
│ │ │ │ │ └── src
│ │ │ │ └── progress.marks
│ │ │ ├── cmake_install.cmake
│ │ │ ├── CTestTestfile.cmake
│ │ │ ├── gtest
│ │ │ │ ├── CMakeFiles
│ │ │ │ │ ├── CMakeDirectoryInformation.cmake
│ │ │ │ │ ├── gtest.dir
│ │ │ │ │ │ ├── build.make
│ │ │ │ │ │ ├── cmake_clean.cmake
│ │ │ │ │ │ ├── DependInfo.cmake
│ │ │ │ │ │ ├── depend.make
│ │ │ │ │ │ ├── flags.make
│ │ │ │ │ │ ├── link.txt
│ │ │ │ │ │ ├── progress.make
│ │ │ │ │ │ └── src
│ │ │ │ │ ├── gtest_main.dir
│ │ │ │ │ │ ├── build.make
│ │ │ │ │ │ ├── cmake_clean.cmake
│ │ │ │ │ │ ├── DependInfo.cmake
│ │ │ │ │ │ ├── depend.make
│ │ │ │ │ │ ├── flags.make
│ │ │ │ │ │ ├── link.txt
│ │ │ │ │ │ ├── progress.make
│ │ │ │ │ │ └── src
│ │ │ │ │ └── progress.marks
│ │ │ │ ├── cmake_install.cmake
│ │ │ │ ├── CTestTestfile.cmake
│ │ │ │ └── Makefile
│ │ │ └── Makefile
│ │ ├── lib
│ │ └── Makefile
│ ├── Makefile
│ └── test_results
├── devel
│ ├── cmake.lock
│ ├── env.sh
│ ├── lib
│ │ ├── cg2111a_talker_listener
│ │ │ ├── listener
│ │ │ └── talker
│ │ ├── pkgconfig
│ │ │ └── cg2111a_talker_listener.pc
│ │ └── python3
│ │ └── dist-packages
│ │ └── cg2111a_talker_listener
│ │ └── __init__.py
│ ├── local_setup.bash
│ ├── local_setup.sh
│ ├── local_setup.zsh
│ ├── setup.bash
│ ├── setup.sh
│ ├── _setup_util.py
│ ├── setup.zsh
│ └── share
│ ├── cg2111a_talker_listener
│ │ └── cmake
│ │ ├── cg2111a_talker_listenerConfig.cmake
│ │ ├── cg2111a_talker_listenerConfig-version.cmake
│ │ ├── cg2111a_talker_listener-msg-extras.cmake
│ │ └── cg2111a_talker_listener-msg-paths.cmake
│ └── roseus
│ └── ros
│ └── cg2111a_talker_listener
│ └── manifest.l
└── src
├── cg2111a_talker_listener
│ ├── CMakeLists.txt
│ ├── include
│ │ └── cg2111a_talker_listener
│ ├── package.xml
│ └── src
│ ├── listener.cpp
│ └── talker.cpp
└── CMakeLists.txt -> /opt/ros/noetic/share/catkin/cmake/toplevel.cmake
92 directories, 305 files
This structure outlines the key components of the ROS workspace:
- build/: Contains intermediate files generated during the build process.
- devel/: Includes executables, libraries, and the
setup.bash
script for environment setup.
-
src/: The source directory for ROS packages. For this tutorial, it houses the
cg2111a_talker_listener
package, which includes:
- CMakeLists.txt: Lists build instructions for the package's nodes.
- package.xml: Defines the package's dependencies and metadata.
- launch/: Contains ROS launch files for starting nodes.
- src/: Source code for the publisher (
talker.cpp
) and subscriber (listener.cpp
) nodes.
This hierarchical view helps in understanding the organization and the relationships between different components of the ROS workspace.
1. Steps for ROS Workspace and Package Creation
-
Create a workspace and build it.
If you have not already created a workspace called cg2111a_exercise_ws
, create one and build it using the following commands:
cd ~
mkdir cg2111a_exercise_ws
cd cg2111a_exercise_ws
mkdir src
cd ~/cg2111a_exercise_ws
catkin_make
This step sets up a ROS workspace, which is a directory where you can develop ROS projects. The catkin_make
command is used to build the workspace, compiling any source files and preparing the environment for ROS nodes.
-
Create a package.
Inside ~/cg2111a_exercise_ws/src
, create a package called cg2111a_talker_listener
using the command:
cd ~/cg2111a_exercise_ws/src
catkin_create_pkg cg2111a_talker_listener std_msgs roscpp
This command creates a new ROS package with the specified name and dependencies. The package will include two important files, CMakeLists.txt
and package.xml
, which are used for building the package and specifying its metadata, respectively.
-
Build the workspace and source the setup file.
Like in Step 1, build the workspace as follows:
cd ~/cg2111a_exercise_ws
catkin_make
Then, source the setup file:
source ./devel/setup.bash
Building the workspace compiles all packages within it, including the newly created package. Sourcing the setup file updates your environment to include paths to the workspace's binaries and scripts, making ROS nodes and tools from this workspace available for use.
-
Check the first-order dependencies.
Before we check the dependencies, we need to install a Python library rosdep
:
sudo pip3 install -U rosdep
Check the first-order dependencies of the package using the command:
rospack depends1 cg2111a_talker_listener
This command lists the direct dependencies of the specified package, reflecting the dependencies declared when the package was created. Understanding these dependencies is crucial for ensuring your package has access to the necessary ROS libraries and messages for its operation.
The result of checking the dependencies should align with the specified dependencies when creating the package. This ensures that your package can interact with ROS correctly and utilize necessary message types and functionalities.
-
Create a new node
talker.cpp
, which will be a publisher.
Inside ~/cg2111a_exercise_ws/src/cg2111a_talker_listener/src
, create and open a file talker.cpp
using the following commands:
cd ~/cg2111a_exercise_ws/src/cg2111a_talker_listener/src
touch talker.cpp
nano talker.cpp
Write the following code into talker.cpp
:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/**
* This tutorial demonstrates simple sending of messages over the ROS system.
*/
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss << "I met student number " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_str());
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
}
Save the file. This code snippet creates a ROS node that publishes a sequence of messages, each containing a string with a counter value. It demonstrates how to send messages within the ROS system and can be used to understand the publishing mechanism.
-
Create a new node
listener.cpp
, which will be a subscriber.
Inside ~/cg2111a_exercise_ws/src/cg2111a_talker_listener/src
, create and open a file listener.cpp
using the same method as before:
touch listener.cpp
nano listener.cpp
For the listener.cpp
, you'll need to write a corresponding subscriber code that listens to the messages published by talker.cpp
. The detailed code for this will involve setting up a subscriber to the "chatter" topic and defining a callback function to process incoming messages.
Write the following code into listener.cpp
:
#include "ros/ros.h"
#include "std_msgs/String.h"
/**
* This tutorial demonstrates simple receipt of messages over the ROS system.
*/
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
ros::spin();
return 0;
}
Save the file. This code sets up a ROS node that subscribes to the "chatter" topic and prints the messages it receives, illustrating how to receive and process messages within the ROS system.
-
Modify
CMakeLists.txt
.
Next, open the CMakeLists.txt
inside ~/cg2111a_exercise_ws/src/cg2111a_talker_listener
:
cd ~/cg2111a_exercise_ws/src/cg2111a_talker_listener
nano CMakeLists.txt
and modify it as detailed below to include the new nodes and their dependencies:
cmake_minimum_required(VERSION 3.0.2)
project(cg2111a_talker_listener)
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
message_generation
genmsg
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
CATKIN_DEPENDS roscpp std_msgs message_runtime
)
include_directories(
include
${catkin_INCLUDE_DIRS}
)
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker cg2111a_talker_listener_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener cg2111a_talker_listener_generate_messages_cpp)
Save the file. These modifications specify the dependencies of your project, ensuring that ROS knows how to correctly build and link the talker and listener nodes within your package.
-
Modify
package.xml
.
Open the package.xml
file inside ~/cg2111a_exercise_ws/src/cg2111a_talker_listener
:
cd ~/cg2111a_exercise_ws/src/cg2111a_talker_listener
nano package.xml
and include the following dependencies:
<?xml version="1.0"?>
<package format="2">
<name>cg2111a_talker_listener</name>
<version>0.0.0</version>
<description>The cg2111a_talker_listener package</description>
<maintainer email="your_email@example.com">Your Name</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>message_generation</build_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
</package>
Save the file. This update includes essential dependencies for building and executing your ROS package, ensuring the package manager recognizes the necessary components for compilation and runtime.
-
Build the workspace and source it.
Refer back to Step 3 for the commands, which are:
cd ~/cg2111a_exercise_ws
catkin_make
This process compiles all the packages within the workspace, including any changes made, and updates the environment to recognize the newly built executables.
-
Running the Publisher (Talker) and Subscriber (Listener).
To simulate the talker and listener communicating, follow these steps:
- Open one terminal and navigate to your workspace:
cd ~/cg2111a_exercise_ws
.
- Run
source ./devel/setup.bash
and roscore
. This starts the ROS master node.
- In a new terminal, navigate to workspace:
cd ~/cg2111a_exercise_ws
and source the setup file with source ./devel/setup.bash
. Run the talker node with rosrun cg2111a_talker_listener talker
.
- In a new terminal, navigate to workspace:
cd ~/cg2111a_exercise_ws
and source the setup file with source ./devel/setup.bash
. Run the talker node with rosrun cg2111a_talker_listener listener
.
You should see the terminal running the talker node publishing a series of messages, and the terminal running the listener node echoing those messages:
Experiment by stopping the listener node (using Ctrl+C) while keeping the talker node running, and observe the behavior. Similarly, stop the talker node while keeping the listener running, and note any differences.
-
Create a launch file. (Optional)
Creating a launch file simplifies the process of starting multiple nodes by using a single command, roslaunch
. Follow these steps to create a launch file:
mkdir -p ~/cg2111a_exercise_ws/src/cg2111a_talker_listener/launch
touch ~/cg2111a_exercise_ws/src/cg2111a_talker_listener/launch/cg2111a_talker_listener.launch
nano ~/cg2111a_exercise_ws/src/cg2111a_talker_listener/launch/cg2111a_talker_listener.launch
Insert the following XML content into the cg2111a_talker_listener.launch
file:
<?xml version="1.0"?>
<launch>
<node pkg="cg2111a_talker_listener" type="talker" name="talker" output="screen" launch-prefix="gnome-terminal --" />
<node pkg="cg2111a_talker_listener" type="listener" name="listener" output="screen" launch-prefix="gnome-terminal --" />
</launch>
This file defines a launch configuration that starts both the talker and listener nodes in separate terminals, facilitating easier management of the ROS nodes.
-
Build the workspace and source it. (Optional)
As done previously, rebuild the workspace and source the setup file to apply the changes:
cd ~/cg2111a_exercise_ws
catkin_make
source ./devel/setup.bash
-
Launch the file. (Optional)
In ~/cg2111a_exercise_ws
, launch the nodes using the following command:
roslaunch cg2111a_talker_listener cg2111a_talker_listener.launch
This command starts the ROS nodes as defined in the launch file, displaying the talker and listener nodes' outputs in separate terminals. You should observe the same behavior as when manually running the nodes in separate terminals, but with the convenience of a single command.
· End of Tutorial ·
★ Bonus Time!
You have done 0 out of 6!
Hip hip hooray! You have successfully learned how to:
- Create a workspace and a package.
- Develop nodes and define messages.
- Utilize nodes and messages to facilitate one-way communication.
- Design and implement a launch file.
You are now have a better understanding of what we do in ROS. Do you want to build up Talkers and Listeners between different devices? Please navigate to Tutorial 4: ROS Networking!
References:
- Dr. Andi Sudjana Putra, Prof. Prahlad Vadakkepat; EE3305/ME3243, AY22/23 Semester I;