Unit3 Part 2
Unit3 Part 2
Unit3 Part 2
Unit 3: Topics
Part 2: Subscriber
You've learned that a topic is a channel where nodes can either write or read information. You've
also seen that you can write into a topic using a publisher, so you may be thinking that there should
also be some kind of similar tool to read information from a topic. And you're right! That's called a
subscriber. A subscriber is a node that reads information from a topic. Let's execute the next
code:
**Example 3.2**
In [ ]:
#! /usr/bin/env python
import rospy
from std_msgs.msg import Int32
def callback(msg):
print msg.data
rospy.init_node('topic_subscriber')
sub = rospy.Subscriber('counter', Int32, callback)
rospy.spin()
**END Python Program {3.2}: simple_topic_subscriber.py**
What's up? Nothing happened again? Well, that's not actually true... Let's do some checks.
Go to your webshell and type the following:
Execute in WebShell #1
In [ ]:
In [ ]:
user ~ $ rostopic echo /counter
WARNING: no messages received and simulated time is active.
Is /clock being published?
And what does this mean? This means that nobody is publishing into the /counter topic, so
there's no information to be read. Let's then publish something into the topic and see what happens.
For that, let's introduce a new command:
In [ ]:
In [ ]:
In [ ]:
Before explaining everything with more detail, let's explain the code you executed.
In [ ]:
#! /usr/bin/env python
import rospy
from std_msgs.msg import Int32
print msg.data # Print the value 'data' inside the 'msg' parameter
sub = rospy.Subscriber('/counter', Int32, callback) # Create a Subscriber object that will listen to the /counter
# topic and will cal the 'callback' function each time it reads
# something from the topic
rospy.spin() # Create a loop that will keep the program in execution
So now, let's explain what has just happened. You've basically created a subscriber node that listens
to the /counter topic, and each time it reads something, it calls a function that does a print of the
msg. Initially, nothing happened since nobody was publishing into the /counter topic, but when you
executed the rostopic pub command, you published a message into the /counter topic, so the
function has printed the number in the IPython's output and you could also see that message in
the rostopic echo output. Now everything makes sense, right?
Now let's do some exercises to put into practice what you've just learned!
**Exercise 3.2**
Create a package that launches the code. Modify the code in order to print the odometry of the
robot.
Follow this link to open the solutions notebook for Unit2 Topics Part2:Topics Part2 Solutions
END Solution Exercise 3.2
**Exercise 3.3**
1. Add to {Exercice 3.2}, a Python file that creates a publisher that indicates the age of the
robot.
2. For that, you'll need to create a new message called Age.msg. To see how you can do that,
have a look at the detailed description How to prepare CMakeLists.txt and package.xml for
custom topic message compilation.
**END Exercise 3.3**
Solution Exercise 3.3
Please Try to do it by yourself unless you get stuck or need some inspiration. You will learn much
more if you fight for each exercise.
Follow this link to open the solutions notebook for Unit 3 Topics Part 2: Topics Part2 Solutions
END Solution Exercise 3.3
roscd <package_name>
mkdir msg
2) The Age.msg file must contain this:
In [ ]:
float32 years
float32 months
float32 days
3) In CMakeLists.txt
You will have to edit four functions inside CMakeLists.txt:
find_package()
add_message_files()
generate_messages()
catkin_package()
I. find_package()
This is where all the packages required to COMPILE the messages of the topics, services, and
actions go. In package.xml, you have to state them as build_depend.
HINT 1: If you open the CMakeLists.txt file in your IDE, you'll see that almost all of the file is
commented. This includes some of the lines you will have to modify. Instead of copying and
pasting the lines below, find the equivalents in the file and uncomment them, and then add
the parts that are missing.
In [ ]:
find_package(catkin REQUIRED COMPONENTS
rospy
std_msgs
message_generation # Add message_generation here, after the other packages
)
II. add_message_files()
This function includes all of the messages of this package (in the msg folder) to be compiled. The file
should look like this.
In [ ]:
add_message_files(
FILES
Age.msg
) # Dont Forget to UNCOMENT the parenthesis and add_message_files TOO
III. generate_messages()
Here is where the packages needed for the messages compilation are imported.
In [ ]:
generate_messages(
DEPENDENCIES
std_msgs
) # Dont Forget to uncoment here TOO
IV. catkin_package()
State here all of the packages that will be needed by someone that executes something from your
package. All of the packages stated here must be in the package.xml as exec_depend.
In [ ]:
catkin_package(
CATKIN_DEPENDS rospy message_runtime # This will NOT be the only thing here
)
Summarizing, this is the minimum expression of what is needed for the CMakelists.txt file to work:
Note: Keep in mind that the name of the package in the following example is topic_ex, so in your
case, the name of the package may be different.
In [ ]:
cmake_minimum_required(VERSION 2.8.3)
project(topic_ex)
add_message_files(
FILES
Age.msg
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
CATKIN_DEPENDS rospy message_runtime
)
include_directories(
${catkin_INCLUDE_DIRS}
)
4) Modify package.xml
Just add these 3 lines to the package.xml file.
In [ ]:
<build_depend>message_generation</build_depend>
<build_export_depend>message_runtime</build_export_depend>
<exec_depend>message_runtime</exec_depend>
This is the minimum expression of the package.xml
Note: Keep in mind that the name of the package in the following example is topic_ex, so in your
case, the name of the package may be different.
In [ ]:
<?xml version="1.0"?>
<package format="2">
<name>topic_ex</name>
<version>0.0.0</version>
<description>The topic_ex package</description>
<maintainer email="user@todo.todo">user</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>message_generation</build_depend>
<build_export_depend>rospy</build_export_depend>
<exec_depend>rospy</exec_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>std_msgs</exec_depend>
<build_export_depend>message_runtime</build_export_depend>
<exec_depend>message_runtime</exec_depend>
<export>
</export>
</package>
5) Now you have to compile the msgs. To do this, you have to type in a WebShell:
Execute in WebShell #1
In [ ]:
roscd; cd ..
catkin_make
source devel/setup.bash
**VERY IMPORTANT**: When you compile new messages, there is still an extra step before you
can use the messages. You have to type in the Webshell, in the **catkin_ws** directory, the
following command: **source devel/setup.bash**.
This executes this bash file that sets, among other things, the newly generated messages created
through the catkin_make.
If you don't do this, it might give you a python import error, saying it doesn't find the message
generated.
HINT 2: To verify that your message has been created successfully, type in your
webshell rosmsg show Age. If the structure of the Age message appears, it will mean that
your message has been created successfully and it's ready to be used in your ROS
programs.
Execute in WebShell #1
In [ ]:
In [ ]:
There is an issue in ROS that could give you problems when importing msgs from the msg directory. If your package has the
same name as the Python file that does the import of the msg, this will give an error saying that it doesn't find the msg
element. This is due to the way Python works. Therefore, you have to be careful to not name the Python file exactly the same
as its parent package.
Example:
Package name = "my_package"
Python file name = "my_package.py"
This will give an import error because it will try to import the messagefrom the my_package.py file, from a directory .msg
that doesn't exists.
Topics Quiz
With all you've learned during this course, you're now able to do a small Quiz to put everything
together. Subscribers, Publisher, Messages... you will need to use all of this concepts in order to
succeed!
For evaluating this Quiz, we will ask you to perform different tasks. For each task, very specific
instructions will be provided: name of the package, names of the launch files and Python scripts,
topic names to use, etc.
It is VERY IMPORTANT that you strictly follow these instructions, since they will allow our
automated correction system to properly test your Quiz, and assign a score to it. If the names you
use are different from the ones specified in the exam instructions, your exercise will be marked
as FAILED, even though it works correctly.
1. Create a Publisher that writes into the /cmd_vel topic in order to move the robot.
2. Create a Subscriber that reads from the /kobuki/laser/scan topic. This is the topic where
the laser publishes its data.
3. Depending on the readings you receive from the laser's topic, you'll have to change the data
you're sending to the /cmd_vel topic in order to avoid the wall. This means, use the values of
the laser to decide.
The logic that your program has to follow is the next one:
1. If the laser reading in front of the robot is higher than 1 meter (there is no obstacle closer
than 1 meter in front of the robot), the robot will move forward.
2. If the laser reading in front of the robot is lower than 1 meter (there is an obstacle closer than
1 meter in front of the robot), the robot will turn left.
3. If the laser reading at the right side of the robot is lower than 1 meter (there is an obstacle
closer than 1 meter at the right side of the robot), the robot will turn left.
4. If the laser reading at the left side of the robot is lower than 1 meter (there is an obstacle
closer than 1 meter at the left side of the robot), the robot will turn right.
The logic explained above has to result in a behavior like the following:
The robot starts moving forward until it detects an obstacle in front of it which is closer than 1 meter.
Then it begins to turn left in order to avoid it.
The robot keeps turning left and moving forward until it detects that it has an obstacle at the right
side which is closer than 1 meter. Then it turns left in order to avoid it.
Finally, the robot will continue moving forward since it won't detect any obstacle (closer than 1
meter) neither in front of it nor in its sides.
HINT 1: The data that is published into the /kobuki/laser/scan topic has a large structure. For
this project, you just have to pay attention to the 'ranges' array.
Execute in WebShell #1
In [ ]:
rosmsg show sensor_msgs/LaserScan
WebShell #1 Output
In [ ]:
chmod +x my_script.py
Quiz Correction
When you have finished the Quiz, you can correct it in order to get a Mark. For that, just click on the
following button at the top of this Notebook.
Final Mark
In case you fail the Quiz, or you don't get the desired mark, do not get frustrated! You will have the
ROS Messages: http://wiki.ros.org/Messages
msg Files: http://wiki.ros.org/msg