-
Notifications
You must be signed in to change notification settings - Fork 2
Basic ROS
Robot Operating System (ROS) is a communication system to exchange message among programs. It is similar to Line application where people can exchange messages. Each person in Line application is a running program which can either wait or send message to other persons. In ROS terminology, each running program is called node. We can think of each node as a person in Line app.

There are three type of communications in ROS.
- Pub/Sub
- Service
- Action
ROS Pub/Sub is the fastest way to exchange messages among nodes. A message can be sent from a node to a node (1:1), a node to many nodes (1:N) or many nodes to many nodes (N:N).

ROS service is similar to ask a question and wait for an answer. An example below shows that the client ask for time from the server and the client is waiting for the answer from the server. It can be used for short processing time task.

For long processing time task, we can use ROS action. The difference between action and service is that ROS action will return progress during waiting time and, hence, the client will know the task progress. The example of ROS action is robot navigation. Since, the robot will take sometime to move from point A to point B, it has to report progress so that the client will know the robot status such as running, finding route or reaching destination.

The following table is ROS command lines to interact with ROS. The star rating indicates that the importance of the commands.

rosnode list is a command to list all running ROS node.
pi@KidBrightAI02:~$ rosnode list
/audio_node
/cam_stream
/rosbridge_websocket
/rosout
/serial_node
/server_stdio
/web_video_server
and rostopic list is a command to show all topics.
pi@KidBrightAI02:~$ rostopic list
/a1
/audio_int
/client_count
/connected_clients
/diagnostics
/output/image_raw/compressed
/rosout
/rosout_agg
/std_done
/std_out
/std_out_python
rostopic info is a command to show information about underlying topic.
pi@raspberrypi:~/kbclientNew/nectec-client/dist/cake $ rostopic info /a1
Type: std_msgs/String
Publishers:
* /audio_stream_761_1642600357700 (http://raspberrypi:36747/)
Subscribers: None
pi@raspberrypi:~/kbclientNew/nectec-client/dist/cake $ rostopic info /output/image_raw/compressed
Type: sensor_msgs/CompressedImage
Publishers:
* /cam_stream (http://raspberrypi:38949/)
Subscribers:
* /web_video_server (http://raspberrypi:34781/)
To check topic activity, we can use rostopic hz
pi@raspberrypi:~/kbclientNew/nectec-client/dist/cake $ rostopic hz /output/image_raw/compressed
subscribed to [/output/image_raw/compressed]
average rate: 10.038
min: 0.096s max: 0.103s std dev: 0.00210s window: 10
average rate: 10.013
min: 0.096s max: 0.103s std dev: 0.00196s window: 20
average rate: 10.011
min: 0.096s max: 0.104s std dev: 0.00212s window: 30
If the topic is inactive
pi@raspberrypi:~/kbclientNew/nectec-client/dist/cake $ rostopic hz /a1
subscribed to [/a1]
no new messages
no new messages
no new messages
no new messages
It can be seen that audio is not working now. Let plug a microphone and try it again.
pi@raspberrypi:~/kbclientNew/nectec-client/dist/cake $ rostopic hz /a1
subscribed to [/a1]
average rate: 19.987
min: 0.046s max: 0.054s std dev: 0.00208s window: 19
average rate: 19.993
min: 0.046s max: 0.054s std dev: 0.00149s window: 40
average rate: 19.931
min: 0.046s max: 0.059s std dev: 0.00168s window: 59
average rate: 19.846
min: 0.046s max: 0.060s std dev: 0.00213s window: 79
average rate: 19.837
min: 0.046s max: 0.060s std dev: 0.00214s window: 99
We can see now audio node is working now.
rosnode info is a command to show information about node.
pi@raspberrypi:~/kbclientNew/nectec-client/dist/cake $ rosnode info /cam_stream
--------------------------------------------------------------------------------
Node [/cam_stream]
Publications:
* /output/image_raw/compressed [sensor_msgs/CompressedImage]
* /rosout [rosgraph_msgs/Log]
Subscriptions: None
Services:
* /cam_stream/get_loggers
* /cam_stream/set_logger_level
contacting node http://raspberrypi:38949/ ...
Pid: 760
Connections:
* topic: /output/image_raw/compressed
* to: /web_video_server
* direction: outbound (37851 - 127.0.0.1:38860) [17]
* transport: TCPROS
* topic: /rosout
* to: /rosout
* direction: outbound (37851 - 127.0.0.1:38806) [16]
* transport: TCPROS
catkin_create_pkg package_name std_msgs rospy roscpp is the command to create ROS package. Let us create a ROS package called tutorial.
First change directory to linorobot_ws/src/
Raspberry pi
pi@raspberrypi:~ $ cd linorobot_ws/src/
NanoPi
cd kidbright_ws/src/
Then create tutorial package
pi@raspberrypi:~/linorobot_ws/src $ catkin_create_pkg tutorial std_msgs rospy roscpp
Created file tutorial/package.xml
Created file tutorial/CMakeLists.txt
Created folder tutorial/include/tutorial
Created folder tutorial/src
Successfully created files in /home/pi/linorobot_ws/src/tutorial. Please adjust the values in package.xml.
Let change directory to tutorial package.
pi@raspberrypi:~/linorobot_ws/src $ cd tutorial
and check the content of tutorial directory
pi@raspberrypi:~/linorobot_ws/src/tutorial $ ls -l
total 20
-rw-r--r-- 1 pi pi 7057 Jan 31 02:03 CMakeLists.txt
drwxr-xr-x 3 pi pi 4096 Jan 31 02:03 include
-rw-r--r-- 1 pi pi 2859 Jan 31 02:03 package.xml
drwxr-xr-x 2 pi pi 4096 Jan 31 02:03 src
src directory if for c++ code
We have to create scripts and srv directories. scripts directory is for python code and srv directory is for ROS service definition.
pi@raspberrypi:~/linorobot_ws/src/tutorial $ mkdir scripts
pi@raspberrypi:~/linorobot_ws/src/tutorial $ mkdir srv
and let check newly created directories.
pi@raspberrypi:~/linorobot_ws/src/tutorial $ ls -l
total 28
-rw-r--r-- 1 pi pi 7057 Jan 31 02:03 CMakeLists.txt
drwxr-xr-x 3 pi pi 4096 Jan 31 02:03 include
-rw-r--r-- 1 pi pi 2859 Jan 31 02:03 package.xml
drwxr-xr-x 2 pi pi 4096 Jan 31 02:11 scripts
drwxr-xr-x 2 pi pi 4096 Jan 31 02:03 src
drwxr-xr-x 2 pi pi 4096 Jan 31 02:11 srv
Create a publisher node using
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
We use talker as a node name and chatter as a topic name. We can then specify publishing rate
rate = rospy.Rate(10) # 10hz
and we start to publish data by
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
The complete code is in /scripts/pub.py and shown below.
#!/usr/bin/env python3
# license removed for brevity
import rospy
from std_msgs.msg import String
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
rate = rospy.Rate(1) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
We need to set permission of pub.py
pi@raspberrypi:~/linorobot_ws/src/tutorial/scripts $ chmod 755 pub.py
then we can test pub.py
pi@raspberrypi:~/linorobot_ws/src/tutorial/scripts $ ./pub.py
[INFO] [1643596631.325158]: hello world 1643596631.3245065
[INFO] [1643596632.326415]: hello world 1643596632.3258057
[INFO] [1643596633.326346]: hello world 1643596633.325707
We can check chatter topic using rostopic list
pi@raspberrypi:~ $ rostopic list
/a1
/audio_int
/chatter
/client_count
/cmd_vel
/connected_clients
/diagnostics
/inputAN
/output
/output/image_raw/compressed
/rosout
/rosout_agg
/save_wave_file/cancel
/save_wave_file/feedback
/save_wave_file/goal
/save_wave_file/result
/save_wave_file/status
/sound_level
/std_done
/std_out
/std_out_python
/voltage
The published data can be monitored by using rostopic echo /chatter
pi@raspberrypi:~ $ rostopic echo /chatter
data: "hello world 1643596862.3257308"
---
data: "hello world 1643596863.3253927"
---
data: "hello world 1643596864.3257298"
---
data: "hello world 1643596865.3249028"
---
data: "hello world 1643596866.3250768"
---
data: "hello world 1643596867.3257227"
---
data: "hello world 1643596868.3257222"
---
data: "hello world 1643596869.3257182"
---
We can now create sub.py for subscriber testing. In subscriber, we need a callback function
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
and we can start to subscribe data by
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
rospy.spin()
It can be seen that we use listener as a node name and chatter as a topic name which is the same in publisher node.
The complete sub.py is listed below.
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
def listener():
# In ROS, nodes are uniquely named. If two nodes with the same
# name are launched, the previous one is kicked off. The
# anonymous=True flag means that rospy will choose a unique
# name for our 'listener' node so that multiple listeners can
# run simultaneously.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()
and We set permission of sub.py
pi@raspberrypi:~/linorobot_ws/src/tutorial/scripts $ chmod 755 sub.py
Now we can use sub.py to listen to chatter
pi@raspberrypi:~/linorobot_ws/src/tutorial/scripts $
pi@raspberrypi:~/linorobot_ws/src/tutorial/scripts $
pi@raspberrypi:~/linorobot_ws/src/tutorial/scripts $ ./sub.py
[INFO] [1643613044.335094]: /listener_6604_1643613043276I heard hello world 1643613044.3257084
[INFO] [1643613045.335134]: /listener_6604_1643613043276I heard hello world 1643613045.325772
[INFO] [1643613046.336760]: /listener_6604_1643613043276I heard hello world 1643613046.3258302
[INFO] [1643613047.335353]: /listener_6604_1643613043276I heard hello world 1643613047.325015
[INFO] [1643613048.335160]: /listener_6604_1643613043276I heard hello world 1643613048.3254073
[INFO] [1643613049.335197]: /listener_6604_1643613043276I heard hello world 1643613049.3257468
[INFO] [1643613050.334861]: /listener_6604_1643613043276I heard hello world 1643613050.325723
[INFO] [1643613051.337672]: /listener_6604_1643613043276I heard hello world 1643613051.32572