ROS 101

ROS basic tutorial


ROS Basic

Publisher & Subscriber

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Node initilization
rospy.init_node(noe_name, anonymous=True, disable_signals=True)

# Create a publisher and publish data
pub = rospy.Publisher(topic_name, data_class)
pub.publish(data)
# Publish at a rate (Hz)
r = rospy.Rate(20)
while not rospy.is_shutdown():
pub.publish(data)
r.sleep()

# Create a subscriber, callback_function will be automatically called when data is published on this topic
rospy.Subscriber(topic_name, data_class, callback_function)

Publisher can't publish immediately after it is created. Need rospy.sleep(1) or use latch.

Messages

1
2
3
4
5
# With latch=True, new subscriber always gets the last message that was published even if the message was published before the subscriber was connected.
pub = rospy.Publisher(topic_name, data_class, latch=True)

# Wait unitl receive message with given datatype in given topic
rospy.wait_for_message(topic_name, data_class)

Create a msg

Make msg directory inside ROS package, create Test.msg file with datatype content, for example:

1
2
3
string a
string b
uint8 c

Add the following two lines to package.xml

1
2
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

Change CMakeList.txt as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
find_package(catkin REQUIRED COMPONENTS
rospy
std_msgs
message_generation
)

catkin_package(
CATKIN_DEPENDS message_runtime ...
)

add_message_files(
FILES
Test.msg
)

generate_messages(
DEPENDENCIES
std_msgs
)

It can be imported by from [package].msg import Test

Service

1
2
# Create a Service
rospy.Service(name, service_class, callback_function)

Create a srv

Similar to msg, create Test.srv in srv/; change package.xml and CMakeLists.txt, the difference is:

1
2
3
4
add_service_files(
FILES
AddTwoInts.srv
)

It can be imported by from [package].srv import Test

Transform

Frames are published on the tf topic.

1
2
3
4
5
6
7
# Find transforms between coordinate frames, rospy.Time(0) will give the latest available transform
tfl = tf.TransformListener()
trans, rot = tfl.lookupTransform(frameid_1, frameid_2, rospy.Time(0))

# Create transforms between frames
pub_tf = tf.TransformBroadcaster()
pub_tf.sendTransform((trans_x, trans_y), quat, rospy.Time.now(), frameid_1, frameid_2)

Launch File & Parameter

1
2
3
4
5
6
7
8
9
10
11
12
13
<launch>
<!-- Use include to run launch files -->
<include file='$(find [package])/[launch]' />

<!-- Define arguments for later use -->
<arg name='arg1' default='true' />

<!-- Run nodes -->
<node pkg='[package]' name='[node_name]' type='[python file]' output='screen'>
<!-- param can be used in file -->
<param name='arg1' value='$(arg arg1)' />
</node>
</launch>

Parameters will be in name domain, for example, the above launch file will create a /node_name/arg1 parameter.

In the python file, arg1 can be read by

1
arg1 = rospy.get_param('~arg1')

~ means in current node name domain.

Visualization

Messages

Visualize messages (values) using MarkerArray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from visualization_msgs.msg import Marker, MarkerArray
import matplotlib.colors as colors

self.pub = rospy.Publisher([topic], MarkerArray, queue_size=50)

# Generate color map and scale by values
norm = colors.Normalize(clip=True)
norm.autoscale(values)
color_map = cm.get_cmap()

markers = MarkerArray()
# Add markers in markerarray
for i, (points, values) in enumerate(zip(points, values)):
marker = Marker()
marker.header.stamp = rospy.Time.now()
marker.header.frame_id = 'map'
# marker.ns = [namespace]
marker.id = i # ids are differenct so they won't replace each other
marker.type = Marker.LINE_STRIP
# marker.action = Marker.ADD

# Here we use points for visualization so that pose and orientation are not required
marker.pose.position.x = 0
marker.pose.position.y = 0
marker.pose.position.z = 0

marker.pose.orientation.x = 0
marker.pose.orientation.y = 0
marker.pose.orientation.z = 0
marker.pose.orientation.w = 1.0

marker.scale.x = 0.02

color = color_map(norm(values))
marker.color.r = color[0]
marker.color.g = color[1]
marker.color.b = color[2]
marker.color.a = color[3]

# Points are only used for markers of type Points, Line strips, and Line/Cube/Sphere lists. It's also used for the Arrow type, if you want to specify the arrow start and end points.
for point in points:
p = Point()
p.x, p.y = point[0], point[1]
marker.points.append(p)

markers.markers.append(marker)

self.pub.publish(markers)

Rviz

Running rviz without parameter will load the config in ~/.rviz/default.rviz

Save rviz config file and use rviz -d [config] will launch Rviz and load the specified config file. This can be integrated in the launch file:

1
2
3
<launch>
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find [package])/[config.rviz]"/>
</launch>

Command Line

File System

1
2
3
4
5
6
7
# Find package location
rospack find [package]

# cd into a package folder
roscd [package]
# cd into ros log files folder
roscd log

Package

Use Catkin Command Line Tools to replace ROS built-in catkin tool.

1
2
3
4
5
6
7
# Build/Clean the entire workspace
catkin build
catkin clean

# List the first-order/all dependencies
rospack depends1 [package]
rospack depends [package]

Run

1
2
3
4
# Run a single node
rosrun [package] [node]
# Run launch file
roslaunch [package] [launch]

Running Info

  • Nodes are just executable files within a ROS package, which can publish/subscribe to Topics or provide/use Services.
  • Topics are for nodes to exchange messages.
  • Services are similar to topics but for RPC (Remote procedure call) request.
  • Messages are simple data structures.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# List all the nodes running
rosnode list
# List infos about a node, such as Publications, Subscriptions and Services
rosnode info [node]
# Clean useless nodes
rosnode cleanup
# Show a dynamic graph of nodes and topics
rosrun rqt_graph rqt_graph

# List all the topics
rostopic list
# Print data published on a topic
rostopic echo [topic]
# List infos about a topic, such as message type, Publishers and Subscribers
rostopic info [topic]

# Show message datatype
rosmsg show/info [msg]

# List all the services
rosservice list
# Call a service
rosservice call [service] [args]

# List all params
rosparam list
# Get/Set params
rosparam get [param]
rosparam set [param] [value]

# See all frames and the nodes publishing them
rosrun tf tf_monitor
# View the connection between frames
rosrun tf view_frames

Rosbag

Filter a recorded rosbag by time:

1
rosbag filter input.bag output.bag "t.secs >= 1531425960 and t.secs <= 1531426140"

Export certain topic from a rosbag to csv/txt:

1
rostopic echo -b [bag_file] -p [topic_name] >> [output_file_name]