ROS (Robot Operating System) Tutorials

Table of Contents

1 安装ROS Indigo

ROS有很多发行版本(Distributions),本文以ROS Indigo Igloo为例介绍其在Ubuntu 14.04中的安装过程。


1.1 Install ros-indigo-desktop-full

$ sudo sh -c 'echo "deb $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
$ sudo apt-key adv --keyserver hkp:// --recv-key 0xB01FA116
$ sudo apt-get update
$ sudo apt-get install ros-indigo-desktop-full

1.2 Initialize rosdep

Before you can use ROS, you will need to initialize rosdep. rosdep enables you to easily install system dependencies for source you want to compile and is required to run some core components in ROS.

$ sudo rosdep init
$ rosdep update

1.3 Environment setup

It's convenient if the ROS environment variables are automatically added to your bash session every time a new shell is launched:

$ echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc
$ source ~/.bashrc

1.4 Getting rosinstall

rosinstall is a frequently used command-line tool in ROS that is distributed separately. It enables you to easily download many source trees for ROS packages with one command.
To install this tool on Ubuntu, run:

$ sudo apt-get install python-rosinstall

2 ROS基本概念

"Programming Robots with ROS"
ROS cheatsheet

2.1 ROS系统的基本结构(ROS graph)

A ROS system is made up of many different programs, running simultaneously, which communicate with each other by passing messages. Visualizing this as a graph, the programs are the nodes, and programs that communicate with each other are connected by edges, typically nodes are POSIX processes and edges are TCP connections.


Figure 1: 一个“取物机器人”的组成(Nodes in the graph represent individual programs; edges represent message streams)

2.1.1 roscore(内置的核心节点/程序)


roscore is a broker that provides connection information to nodes so that they can transmit messages to each other.

2.2 节点间通信——Topics

ROS systems consist of a number of independent nodes that comprise a graph. These nodes by themselves are typically not very useful. Things only get interesting when nodes communicate with each other, exchanging information and data. The most common way to do that is through topics. A topic is a name for a stream of messages with a defined. For example, the data from a laser range- finders might be send on a topic called scan, with a message type of LaserScan, while the data from a camera might be sent over a topic called image, with a message type of Image.

Before they can start to transmit data over topics, nodes must first announce, or advertize, both the topic name and the type of messages that are going to be sent. Then they can start to send, or publish, the actual data on the topic. Nodes that want to receive messages on a topic can subscribe to that topic by making a request to roscore. After subscribing, all messages on the topic are delivered to the node that make the request. Topics implement a publish/subcribe communications mechanism.


Figure 2: ROS topic(摘自


2.3 节点间通信——Services(同步,类似于RPC)

Services are another way to pass data between nodes in ROS. Services are really just synchronous remote procedure calls; they allow one node to call a function in another node.

2.4 节点间通信——Actions(异步,适应于耗时操作)


ROS actions are the best way to implement interfaces to time-extended goal-oriented behaviors like 'goto_position'. While services are synchronous, actions are asynchronous (actions are implemented atop topics). Similar to the request and response of a service, an action uses a goal to initiate a behavior and sends a result when the behavior is complete. But the action further uses feedback to provide updates on the behavior’s progress toward the goal and also allows for goals to be canceled.

3 ROS工程的目录结构

3.1 什么是Package和Workspace

Packages form the atomic level of ROS. A package has the minimum structure and content to create a program within ROS. It may have ROS runtime processes (nodes), configuration files, and so on.

The workspace is a folder where we have packages, edit the source files or compile packages.

3.2 catkin(ROS官方编译系统,rosbuild的继承者)

catkin is the official build system of ROS and the successor to the original ROS build system, rosbuild.
catkin使用 package.xml 作为“功能包”的配置文件(rosbuild使用manifest.xml作为“功能包”的配置文件)。

说明:stack概念在catkin中已经过时,请使用metapackages。请参考: Goodbye Stacks, Hello Metapackages

3.3 catkin workspace的目录结构

A catkin workspace is a folder where you modify, build, and install catkin packages. It is specified in REP 128.

一个catkin workspace的典型目录结构如下:

workspace_folder/         -- WORKSPACE
  src/                    -- SOURCE SPACE
    CMakeLists.txt        -- The 'toplevel' CMake file
  build/                  -- BUILD SPACE
    CATKIN_IGNORE         -- Keeps catkin from walking this directory
  devel/                  -- DEVELOPMENT SPACE (set by CATKIN_DEVEL_PREFIX)
  install/                -- INSTALL SPACE (set by CMAKE_INSTALL_PREFIX)

3.4 实例:创建catkin workspace

可用 catkin_init_workspace 创建Workspaces,如:

$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
Creating symlink "/home/cig01/catkin_wc/src/CMakeLists.txt" pointing to "/opt/ros/indigo/share/catkin/cmake/toplevel.cmake"

上面例子中 catkin_init_workspace 的作用仅仅是在当前目录中创建了CMakeLists.txt的软链接。


3.5 实例:创建catkin package

可用 catkin_create_pkg 方法创建Packages,如:

$ cd ~/catkin_ws/src
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

说明:上面操作中创建了功能包beginner_tutorials(并设置这个功能包依赖于另外3个功能包std_msgs rospy roscpp),生成的文件(如package.xml,CMakeLists.txt)都存放在新创建的子目录beginner_tutorials中。


3.6 实例:编译workspace中的packages

在workspace根目录用 [[][catkin_make]] 可编译workspace中的packages,如:

$ cd ~/catkin_ws
$ catkin_make

3.7 Package相关实用工具(rospack, roscd, rosls)

工具名称 用法 作用
rospack rospack <command> [options] [package] 查询Package相关信息
roscd roscd <package-or-stack>[/subdir] 直接进入Package目录(或其子目录)
rosls rosls <package-or-stack>[/subdir] 查看Package目录(或其子目录)的内容


3.7.1 rospack

rospack 可以查询Package相关信息。基本格式为: rospack <command> [options] [package]

rospack中最常用的命令是 rospack find package-name ,用于查询包 package-name 的安装位置。


$ rospack find roscpp                                  # 查询包 roscpp 的安装位置
$ rospack list |grep gazebo                            # 查询和 gazebo 相关的包及其安装位置
gazebo_msgs /opt/ros/indigo/share/gazebo_msgs
gazebo_plugins /opt/ros/indigo/share/gazebo_plugins
gazebo_ros /opt/ros/indigo/share/gazebo_ros

4 Tutorials

4.1 Topic实例:Writing a Simple Publisher and Subscriber

这个实例摘自: Writing a Simple Publisher and Subscriber (C++)

这个教程将演示Topic的基本使用。下面会创建两个Node,一个作为Publisher(发送消息hello world),另一个作为Subscriber(接收消息)。

4.1.1 准备Publisher节点的代码


$ cd ~/catkin_ws/src/beginner_tutorials
$ mkdir -p ~/catkin_ws/src/beginner_tutorials/src


// file talker.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"

#include <sstream>

int main(int argc, char **argv)
  ros::init(argc, argv, "talker");

   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
  ros::NodeHandle n;

   * The advertise() function is how you tell ROS that you want to
   * publish on a given topic name. This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing. After this advertise() call is made, the master
   * node will notify anyone who is trying to subscribe to this topic name,
   * and they will in turn negotiate a peer-to-peer connection with this
   * node.  advertise() returns a Publisher object which allows you to
   * publish messages on that topic through a call to publish().  Once
   * all copies of the returned Publisher object are destroyed, the topic
   * will be automatically unadvertised.
  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 << "hello world " << count; = ss.str();


     * The publish() function is how you send messages. The parameter
     * is the message object. The type of this object must agree with the type
     * given as a template parameter to the advertise<>() call, as was done
     * in the constructor above.

    /* Calling ros::spinOnce() here is not necessary for this simple program


  return 0;

4.1.2 准备Subscriber节点的代码


// file 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");

   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
  ros::NodeHandle n;

   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.

  return 0;

4.1.3 编译Nodes


include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)

然后,在workspace根目录,运行 catkin_make 进行编译,如:

$ catkin_make
Base path: /home/cig01/catkin_ws
Source space: /home/cig01/catkin_ws/src
Build space: /home/cig01/catkin_ws/build
Devel space: /home/cig01/catkin_ws/devel
Install space: /home/cig01/catkin_ws/install
#### Running command: "make cmake_check_build_system" in "/home/cig01/catkin_ws/build"
-- Using CATKIN_DEVEL_PREFIX: /home/cig01/catkin_ws/devel
-- Using CMAKE_PREFIX_PATH: /opt/ros/indigo
-- This workspace overlays: /opt/ros/indigo
-- Using PYTHON_EXECUTABLE: /usr/bin/python
-- Using Debian Python package layout
-- Using empy: /usr/bin/empy
-- Call enable_testing()
-- Using CATKIN_TEST_RESULTS_DIR: /home/cig01/catkin_ws/build/test_results
-- Found gtest sources under '/usr/src/gtest': gtests will be built
-- Using Python nosetests: /usr/bin/nosetests-2.7
-- catkin 0.6.16
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~  traversing 1 packages in topological order:
-- ~~  - beginner_tutorials
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin package: 'beginner_tutorials'
-- ==> add_subdirectory(beginner_tutorials)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/cig01/catkin_ws/build
#### Running command: "make -j1 -l1" in "/home/cig01/catkin_ws/build"
Scanning dependencies of target listener
[ 50%] Building CXX object beginner_tutorials/CMakeFiles/listener.dir/src/listener.cpp.o
Linking CXX executable /home/cig01/catkin_ws/devel/lib/beginner_tutorials/listener
[ 50%] Built target listener
Scanning dependencies of target talker
[100%] Building CXX object beginner_tutorials/CMakeFiles/talker.dir/src/talker.cpp.o
Linking CXX executable /home/cig01/catkin_ws/devel/lib/beginner_tutorials/talker
[100%] Built target talker



4.1.4 运行Nodes进行测试

第一步,确保核心程序 roscore 已经运行,如果没有运行,请用下面命令启动它:

$ roscore &


$ cd ~/catkin_ws
$ source ./devel/setup.bash

第三步,用 [[][rosrun]] 启动节点publisher(也就是talker), rosrun 命令的基本格式为 rosrun <package> <executable> 。在这个例子中,启动节点的命令如下:

$ rosrun beginner_tutorials talker
[ INFO] [1430732181.510479169]: hello world 0
[ INFO] [1430732181.610567787]: hello world 1
[ INFO] [1430732181.710586980]: hello world 2
[ INFO] [1430732181.810581019]: hello world 3
[ INFO] [1430732181.910600488]: hello world 4
[ INFO] [1430732182.010723126]: hello world 5
[ INFO] [1430732182.110596785]: hello world 6
[ INFO] [1430732182.211556940]: hello world 7
[ INFO] [1430732182.310633424]: hello world 8

talker程序会一直在终端上输出"hello world",直到按Ctrl+C退出。

第四步,打开另外一个终端,用 rosrun 启动节点subscriber(也就是listener),如:

$ cd ~/catkin_ws
$ source ./devel/setup.bash
$ rosrun beginner_tutorials listener
[ INFO] [1430732304.262828995]: I heard: [hello world 21]
[ INFO] [1430732304.363368221]: I heard: [hello world 22]
[ INFO] [1430732304.463365431]: I heard: [hello world 23]
[ INFO] [1430732304.562538918]: I heard: [hello world 24]
[ INFO] [1430732304.662391090]: I heard: [hello world 25]
[ INFO] [1430732304.762429223]: I heard: [hello world 26]
[ INFO] [1430732304.862479712]: I heard: [hello world 27]
[ INFO] [1430732304.963490914]: I heard: [hello world 28]
[ INFO] [1430732305.062607461]: I heard: [hello world 29]
[ INFO] [1430732305.163459575]: I heard: [hello world 30]
[ INFO] [1430732305.262455761]: I heard: [hello world 31]
[ INFO] [1430732305.362392775]: I heard: [hello world 32]
[ INFO] [1430732305.462446132]: I heard: [hello world 33]

可以看到,listener接收到了"hello world"的消息。

4.2 Service实例:Writing a Simple Service and Client

这个实例摘自: Writing a Simple Service and Client (C++)


4.2.1 创建和编译srv文件



$ cd ~/catkin_ws/src/beginner_tutorials
$ mkdir srv


int64 a
int64 b
int64 sum





find_package(catkin REQUIRED COMPONENTS


find_package(catkin REQUIRED COMPONENTS




第四步:用工具 rossrv 测试新增加的srv文件。

$ ~/catkin_ws/src/beginner_tutorials$ rossrv show beginner_tutorials/AddTwoInts
int64 a
int64 b
int64 sum

catkin_make 编译srv文件为头文件。如:

$ cd ~/catkin_ws/
$ catkin_make install


4.2.2 准备Service节点的代码


$ cd ~/catkin_ws/src/beginner_tutorials


#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

bool add(beginner_tutorials::AddTwoInts::Request  &req,
         beginner_tutorials::AddTwoInts::Response &res)
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("sending back response: [%ld]", (long int)res.sum);
  return true;

int main(int argc, char **argv)
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  ROS_INFO("Ready to add two ints.");

  return 0;

4.2.3 准备Client节点的代码


#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>

int main(int argc, char **argv)
  ros::init(argc, argv, "add_two_ints_client");
  if (argc != 3)
    ROS_INFO("usage: add_two_ints_client X Y");
    return 1;

  ros::NodeHandle n;
  ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
  beginner_tutorials::AddTwoInts srv;
  srv.request.a = atoll(argv[1]);
  srv.request.b = atoll(argv[2]);
  if (
    ROS_INFO("Sum: %ld", (long int)srv.response.sum);
    ROS_ERROR("Failed to call service add_two_ints");
    return 1;

  return 0;

4.2.4 编译Nodes


## If following line does not exist, uncomment it.
# include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(add_two_ints_server src/add_two_ints_server.cpp)
target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
add_dependencies(add_two_ints_server beginner_tutorials_gencpp)

add_executable(add_two_ints_client src/add_two_ints_client.cpp)
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})
add_dependencies(add_two_ints_client beginner_tutorials_gencpp)

然后,在workspace根目录,运行 catkin_make 进行编译,如:

$ cd ~/catkin_ws
$ catkin_make



4.2.5 运行Nodes进行测试

第一步,确保核心程序 roscore 已经运行,如果没有运行,请用下面命令启动它:

$ roscore &


$ cd ~/catkin_ws
$ source ./devel/setup.bash


$ rosrun beginner_tutorials add_two_ints_server
[ INFO] [1430794215.139844241]: Ready to add two ints.


$ source ./devel/setup.bash
$ rosrun beginner_tutorials add_two_ints_client 10 20
[ INFO] [1430794249.352988484]: Sum: 30

4.3 用roslaunch启动Service实例中节点

roslaunch is a tool for easily launching multiple ROS nodes locally and remotely via SSH.
当节点比较多时,一个一个启动将非常地麻烦,这时工具 roslaunch 就派上用场了,它使用后缀为.launch的文件作为配置文件。



$ cd ~/catkin_ws
$ source devel/setup.bash
$ roscd beginner_tutorials
$ mkdir launch


     <node name ="add_two_ints_server" pkg="beginner_tutorials"  type="add_two_ints_server" />
     <node name ="add_two_ints_client_1" pkg="beginner_tutorials"  type="add_two_ints_client" args="10 20" />
     <node name ="add_two_ints_client_2" pkg="beginner_tutorials"  type="add_two_ints_client" args="30 40" />

roslaunch 启动文件test_srv.launch中配置的节点:

$ roslaunch launch/test_srv.launch
    add_two_ints_client_1 (beginner_tutorials/add_two_ints_client)
    add_two_ints_client_2 (beginner_tutorials/add_two_ints_client)
    add_two_ints_server (beginner_tutorials/add_two_ints_server)

auto-starting new master
process[master]: started with pid [3656]

setting /run_id to 2170226a-c40e-11e5-8dce-080027d30e2b
process[rosout-1]: started with pid [3669]
started core service [/rosout]
process[add_two_ints_server-2]: started with pid [3676]
process[add_two_ints_client_1-3]: started with pid [3688]
process[add_two_ints_client_2-4]: started with pid [3692]
[add_two_ints_client_1-3] process has finished cleanly
log file: /home/cig01/.ros/log/2170226a-c40e-11e5-8dce-080027d30e2b/add_two_ints_client_1-3*.log
[add_two_ints_client_2-4] process has finished cleanly
log file: /home/cig01/.ros/log/2170226a-c40e-11e5-8dce-080027d30e2b/add_two_ints_client_2-4*.log

roslaunch 的输出中,可以看到节点已经执行并结束,我们检测节点的日志,可以看到Service(对两个整数相加)已经成功调用:

$ cat /home/cig01/.ros/log/2170226a-c40e-11e5-8dce-080027d30e2b/add_two_ints_client_1-3-stdout.log
[ INFO] [1430800067.983614134]: Sum: 30
$ cat /home/cig01/.ros/log/2170226a-c40e-11e5-8dce-080027d30e2b/add_two_ints_client_2-4-stdout.log
[ INFO] [1430800067.997234796]: Sum: 70

5 Parameter Server

A parameter server is a shared, multi-variate dictionary that is accessible via network APIs. Nodes use this server to store and retrieve parameters at runtime. As it is not designed for high-performance, it is best used for static, non-binary data such as configuration parameters.

The Parameter Server is implemented using XMLRPC and runs inside of the ROS Master (roscore). 启动roscore后,就已经有Parameter Server在运行了。

5.1 rosparam(用于操作参数)

The rosparam command-line tool enables you to query and set parameters on the Parameter Server using YAML syntax.

Table 1: rosparam相关命令
rosparam相关命令 描述
rosparam set set parameter
rosparam get get parameter
rosparam load load parameters from file
rosparam dump dump parameters to file
rosparam delete delete parameter
rosparam list list parameter names


$ roscore &
$ rosparam list                 # 列出所有可用参数
$ rosparam get /rosdistro       # 查询参数 /rosdistro


$ rosparam set /foo 1.3         # 设置参数 /foo 不存在就新增
$ rosparam get /foo             # 查询参数 /foo
$ rosparam list
$ rosparam delete /foo          # 删除参数 /foo
$ rosparam get /foo
ERROR: Parameter [/foo] is not set

6 rqt

rqt is a Qt-based framework for GUI development for ROS.

在shell中执行 rqt 可以启动它。


Figure 3: rqt主界面

rqt中的一些常用工具,也可以直接在shell中启动。如,在运行前面的Topic实例时,启动 rqt_graph 可得到下面的图示:


Figure 4: rqt_graph实例

7 turtlesim

turtlesim is a tool made for teaching ROS and ROS packages.


$ roscore


$ rosmake turtlesim
$ rosrun turtlesim turtlesim_node



Figure 5: TurtleSim

Author: cig01

Created: <2015-05-03 Sun 00:00>

Last updated: <2016-10-11 Tue 22:00>

Creator: Emacs 25.1.1 (Org mode 9.0.7)