#1. Installing and Configuring Your ROS Environment
rosws
rosws is part of the rosinstall package. See py-rosws-stacks.]
##Managing Your Environment
在安装过程中ROS的,你会看到提示您激活几个设setup.*sh文件,甚至将这种“激活”添加到你的shell启动脚本。这是必需的,因为ROS依赖于使用shell环境组合空间的概念。这使得针对不同版本的ROS或针对不同的包集合进行开发更容易。
如果您在查找或使用ROS软件包时遇到问题,请确保正确设置环境。检查的一个好方法是确保设置ROS_ROOT和ROS_PACKAGE_PATH等环境变量:
$ printenv | grep ROS
ROS_ROOT
sets the location where the ROS core packages are installed.
export ROS_ROOT=/home/user/ros/ros
export PATH=$ROS_ROOT/bin:$PATH
ROS_PACKAGE_PATH
是一个可选但非常常见的环境变量,允许您从源向环境添加更多ROS包。ROS_PACKAGE_PATH
可以由一个或多个由标准OS路径分隔符分隔的路径组成(例如,类Unix系统上的’:’)。这些有序路径告诉ROS系统在哪里搜索更多ROS包。如果有相同名称的多个包,ROS会选择上出现的一个ROS_PACKAGE_PATH
第一。
export ROS_PACKAGE_PATH = / home / user / ros / ros-pkg:/ another / path
请注意,ROS_PACKAGE_PATH
中的每个条目都是递归搜索的 - 将找到命名路径下的所有ROS包。
随着catkin
的引入,ROS_PACKAGE_PATH
变得过时,并且仅为了向后兼容rosbuild
包而保留。
If you just installed ROS from apt on Ubuntu then you will have setup.*sh
files in/opt/ros/
, and you could source them like so:
$ source /opt/ros//setup.bash
Using the short name of your ROS distribution instead of
If you installed ROS Kinetic, that would be:
$ source /opt/ros/kinetic/setup.bash
You will need to run this command on every new shell you open to have access to the ROS commands, unless you add this line to your .bashrc
. This process allows you to install several ROS distributions (e.g. indigo
and kinetic
) on the same computer and switch between them.
##Create a ROS Workspace
Let’s create and build a catkin workspace:
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/
$ catkin_make
在“devel”文件夹中,您可以看到现在有几个setup。* sh文件。获取这些文件中的任何一个都会将此工作区覆盖在您的环境之上
source your new setup.*sh file:
$ source devel / setup.bash
要确保设置脚本正确覆盖您的工作区,请确保ROS_PACKAGE_PATH
环境变量包含您所在的目录。
$ echo $ROS_PACKAGE_PATH
/home/youruser/catkin_ws/src:/opt/ros/kinetic/share
catkin包可以构建为独立项目,与构建普通cmake项目的方式相同,但catkin还提供了工作空间的概念,您可以在其中同时构建多个相互依赖的包。
一个catkin工作区最多可包含四个不同的空间,每个服务在软件开发过程中不同的角色。
source space
build space
development space
install space
result space
(either be a development space or an install space)
Overlays(覆盖)
二进制catkin包中包含一组用于扩展shell环境的环境设置文件,以便您可以查找和使用已安装到本地的任何资源。
you must source the setup file included in the root of the distribution install directory (usually /opt/ros/
/
opt/
ros/
kinetic/
setup.bash -- Environment setup file for Bash shell
setup.sh -- Environment setup file for Bourne shell
setup.zsh -- Environment setup file for zshell
...
To setup your environment to use the /opt/ros/kinetic installation space, source the setup file for your shell:
source /opt/ros/kinetic/setup.bash
##Prerequisites
$ sudo apt-get install ros--ros-tutorials
Replace '
###Filesystem Tools
代码分布在许多ROS包中。使用命令行工具(如ls和cd)进行导航可能非常繁琐,这也是ROS提供工具来帮助您的原因。
####使用rospack
rospack
允许您获取有关包的信息。在本教程中,我们将仅介绍find选项,它返回package的路径
用法:
$ rospack find [package_name]
例如:
$ rospack find roscpp
/opt/ros/kinetic/share/roscpp
####Using roscd
roscd is part of the rosbash suite. It allows you to change directory (cd) directly to a package or a stack.
例如:
qy@QY:~/catkin_ws2$ roscd roscpp
qy@QY:/opt/ros/kinetic/share/roscpp$
Now let’s print the working directory using the Unix command pwd
:
qy@QY:/opt/ros/kinetic/share/roscpp$ pwd
/opt/ros/kinetic/share/roscpp
Note that roscd, like other ROS tools, will only find ROS packages that are within the directories listed in your ROS_PACKAGE_PATH
. To see what is in your ROS_PACKAGE_PATH
, type:
$ echo $ROS_PACKAGE_PATH
例如:
$ echo $ROS_PACKAGE_PATH
/home/qy/catkin_ws2/src:/opt/ros/kinetic/share
Similarly to other environment paths, you can add additional directories to your ROS_PACKAGE_PATH, with each path separated by a colon ‘:’
Subdirectories
roscd can also move to a subdirectory of a package or stack.
Try:
$ roscd roscpp/cmake
$ pwd
/opt/ros/kinetic/share/roscpp/cmake
roscd log
roscd log will take you to the folder where ROS stores log files
$ roscd log
Using rosls
rosls is part of the rosbash suite. It allows you to ls directly in a package by name rather than by absolute path.
Usage:
$ rosls [locationname[/subdir]]
例如:
$ rosls roscpp_tutorials
would return:
cmake launch package.xml srv
###Tab Completion(标签完成)
It can get tedious(繁琐的) to type out an entire package name. In the previous example, roscpp_tutorials is a fairly(十分) long name. Luckily, some ROS tools support TAB completion.
#3.Creating a ROS Package
说明:本教程介绍使用roscreate-PKG或cakin创建一个新包,rospack列出软件包的依赖。
###3.1. What makes up a catkin Package?
对于一个catkin package 必须要满足一下几个要求:
my_package/
CMakeLists.txt
package.xml
#3.2 Packages in a catkin Workspace
推荐使用catkin workspace
来管理catkin packages,但是你也可以单独地建立catkin packages.一个常见的空间是下面这个样子:
workspace_folder/ -- WORKSPACE
src/ -- SOURCE SPACE
CMakeLists.txt -- 'Toplevel' CMake file, provided by catkin
package_1/
CMakeLists.txt -- CMakeLists.txt file for package_1
package.xml -- Package manifest for package_1
...
package_n/
CMakeLists.txt -- CMakeLists.txt file for package_n
package.xml -- Package manifest for package_n
3…3 Creating a catkin Package
如何使用catkin_create_pkg
脚本创建一个新的catkin package
# You should have created this in the Creating a Workspace Tutorial
$ cd ~/catkin_ws/src
使用 catkin_create_pkg 脚本来创建一个名为beginner_tutorials
(依赖于std_msgs roscpp和rospy
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
这会创建一个beginner_tutorials 文件夹,它包含了package.xml和CMakeLists.txt,其中一些内容是通过 给 catkin_create_pkg 的信息来填入的.
catkin_create_pkg requires that you give it a package_name and optionally a list of dependencies on which that package depends:
# This is an example, do not try to run this
# catkin_create_pkg [depend1] [depend2] [depend3]
###3.4.Building a catkin workspace and sourcing the setup file
$ cd ~/catkin_ws
$ catkin_make
After the workspace has been built it has created a similar structure in the devel subfolder as you usually find under /opt/ros/$ROSDISTRO_NAME.
To add the workspace to your ROS environment you need to source the generated setup file:
$ . ~/catkin_ws/devel/setup.bash
###3.5 package dependencies
First-order dependencies(一阶依赖)
When using catkin_create_pkg earlier, a few package dependencies were provided. These first-order dependencies can now be reviewed with the rospack tool.
$ rospack depends1 beginner_tutorials
结果:
roscpp
rospy
std_msgs
These dependencies for a package are stored in the package.xml file:
$ roscd beginner_tutorials
$ cat package.xml
...
catkin
roscpp
rospy
std_msgs
...
Indirect dependencies
In many cases, a dependency will also have its own dependencies. For instance, rospy has other dependencies.
$ rospack depends1 rospy
genpy
roscpp
rosgraph
rosgraph_msgs
roslib
std_msgs
A package can have quite a few indirect dependencies. Luckily rospack can recursively determine all nested dependencies.
$ rospack depends beginner_tutorials
###3.6Customizing Your Package
3.6.1Customizing the package.xml
description tag
5 The beginner_tutorials package
描述用一行话,否则会出错.
maintainer tags
7
8
9
10 user
The name of the maintainer goes into the body of the tag, but there is also an email attribute that should be filled out.
license tags
12
13
14
15 TODO
For this tutorial we’ll use the BSD license because the rest of the core ROS components use it already:
8 BSD
dependencies tags
The dependencies are split into build_depend, buildtool_depend, exec_depend, test_depend.
Since we passed std_msgs, roscpp, and rospy as arguments to catkin_create_pkg, the dependencies will look like this:
27
28
29
30
31
32
33
34
35
36
37
38 catkin
39 roscpp
40 rospy
41 std_msgs
In this case we want all of our specified dependencies to be available at build and run time, so we’ll add a exec_depend tag for each of them as well:
12 catkin
13
14 roscpp
15 rospy
16 std_msgs
17
18 roscpp
19 rospy
20 std_msgs
Final package.xml
As you can see the final package.xml, without comments and unused tags, is much more concise:
1
2
3 beginner_tutorials
4 0.1.0
5 The beginner_tutorials package
6
7 Your Name
8 BSD
9 http://wiki.ros.org/beginner_tutorials
10 Jane Doe
11
12 catkin
13
14 roscpp
15 rospy
16 std_msgs
17
18 roscpp
19 rospy
20 std_msgs
21
22
3.6.2 Customizing the CMakeLists.txt
The CMakeLists.txt file created by catkin_create_pkg will be covered in the later tutorials about building ROS code.
#4.Building a ROS Package
###4.1Building Packages
$ source /opt/ros/kinetic/setup.bash # For Kinetic for instance
Using catkin_make
可以想象catkin_make将调用cmake和make组合在标准CMake工作流中。
# In a catkin workspace
$ catkin_make [make_targets] [-DCMAKE_VARIABLES=...]
CMake workflow, it breaks down as follows:
# In a CMake project
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install # (optionally)
Building zero to many catkin packages in a workspace follows this work flow:
# In a catkin workspace
$ catkin_make
$ catkin_make install # (optionally)
If your source code is in a different place, say my_src then you would call catkin_make like this:
# In a catkin workspace
$ catkin_make --source my_src
$ catkin_make install --source my_src # (optionally)
###4.2Building Your Package
$ cd ~/catkin_ws/
$ ls src
We can now build that package using catkin_make:
$ catkin_make
The build folder is the default location of the build space and is where cmake and make are called to configure and build your packages. The devel folder is the default location of the devel space, which is where your executables and libraries go before you install your packages.
#5 Understanding ROS Nodes
Description: This tutorial introduces ROS graph concepts and discusses the use of roscore, rosnode, and rosrun commandline tools
###Quick Overview of Graph Concepts:
rospy = python client library
roscpp = c++ client library
###roscore
roscore is the first thing you should run when using ROS.
$ roscore
###Using rosnode
Bare in mind to keep the previous terminal open either by opening a new tab or simply minimizing it.
$ rosnode list
You will see:
/rosout
This is always running as it collects and logs nodes’ debugging output.
The rosnode info command returns information about a specific node.
$ rosnode info /rosout
###Using rosrun
rosrun allows you to use the package name to directly run a node within a package (without having to know the package path).
$ rosrun [package_name] [node_name]
so:
$ rosrun turtlesim turtlesim_node
In a new terminal:
$ rosnode list
You will see something similar to:
/rosout
/turtlesim
One powerful feature of ROS is that you can reassign Names from the command-line.
$ rosrun turtlesim turtlesim_node __name:=my_turtle
$ rosnode list
will see:
/my_turtle
/rosout
Note: If you still see/turtlesim
in the list, it might mean that you stopped the node in the terminal using ctrl-C instead of closing the window, or that you don’t have the $ROS_HOSTNAME
environment variable defined as described in Network Setup - Single Machine Configuration. You can try cleaning the rosnode list with: $ rosnode cleanup
We see our new /my_turtle node. Let’s use another rosnode command, ping, to test that it’s up(测试是否工作):
$ rosnode ping my_turtle
###Review
What was covered:
roscore = ros+core : master (provides name service for ROS) + rosout (stdout/stderr) + parameter server (parameter server will be introduced later)
rosnode = ros+node : ROS tool to get information about a node.
rosrun = ros+run : runs a node from a given package.
#6 Understanding ROS Topics
Setup
Let’s start by making sure that we have roscore running, in a new terminal:
$ roscore
turtlesim:
$ rosrun turtlesim turtlesim_node
turtle keyboard teleoperation
$ rosrun turtlesim turtle_teleop_key
ROS Topics
Using rqt_graph
$ rosrun rqt_graph rqt_graph
Introducing rostopic
$ rostopic -h
rostopic bw display bandwidth used by topic
rostopic echo print messages to screen
rostopic hz display publishing rate of topic
rostopic list print information about active topics
rostopic pub publish data to topic
rostopic type print topic type
Using rostopic echo
rostopic echo [topic]
$ rostopic echo /turtle1/cmd_vel
Using rostopic list
For rostopic list use the verbose option:
$ rostopic list -v
ROS Messages
通过在节点之间发送ROS 消息来进行主题通信。对于要发布的发布者(turtle_teleop_key)和订阅者(turtlesim_node),发布者和订阅者必须发送和接收相同类型的消息。This means that a topic type is defined by the message type published on it. The type of the message sent on a topic can be determined using rostopic type.
Using rostopic type
rostopic type [topic]
$ rostopic type /turtle1/cmd_vel
得到:
geometry_msgs/Twist
We can look at the details of the message using rosmsg:
$ rosmsg show geometry_msgs/Twist
rostopic continued
Using rostopic pub
rostopic pub publishes data on to a topic currently advertised.
Usage:
rostopic pub [topic] [msg_type] [args]
$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
explain:
This command will publish messages to a given topic:
rostopic pub
This option (dash-one) causes rostopic to only publish one message then exit:
-1
This is the name of the topic to publish to:
/turtle1/cmd_vel
This is the message type to use when publishing to the topic:
geometry_msgs/Twist
his option (double-dash) tells the option parser that none of the following arguments is an option. This is required in cases where your arguments have a leading dash -, like negative numbers.
As noted before, a geometry_msgs/Twist msg has two vectors of three floating point elements each: linear and angular. In this case, ‘[2.0, 0.0, 0.0]’ becomes the linear value with x=2.0, y=0.0, and z=0.0, and ‘[0.0, 0.0, 1.8]’ is the angular value with x=0.0, y=0.0, and z=1.8. These arguments are actually in YAML syntax, which is described more in the YAML command line documentation.
'[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'
You may have noticed that the turtle has stopped moving; this is because the turtle requires a steady stream of commands at 1 Hz to keep moving. We can publish a steady stream of commands using rostopic pub -r command:
$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
Using rostopic hz
rostopic hz reports the rate at which data is published.
Usage:
rostopic hz [topic]
Let’s see how fast the turtlesim_node is publishing /turtle1/pose:
$ rostopic hz /turtle1/pose
$ rostopic type /turtle1/cmd_vel | rosmsg show
Using rqt_plot
$ rosrun rqt_plot rqt_plot
in a new terminal. In the new window that should pop up, a text box in the upper left corner gives you the ability to add any topic to the plot. Typing/turtle1/pose/x
will highlight the plus button, previously disabled. Press it and repeat the same procedure with the topic /turtle1/pose/y
. You will now see the turtle’s x-y location plotted in the graph.
#7.Understanding ROS Services and Parameters
Description: This tutorial introduces ROS services, and parameters as well as using the rosservice and rosparam commandline tools.
目录
ROS Services
Using rosservice
rosservice list
rosservice type
rosservice call
Using rosparam
rosparam list
rosparam set and rosparam get
rosparam dump and rosparam load
Assuming your turtlesim_node is still running from the last tutorial, let’s look at what services the turtlesim provides:
ROS Services
Services are another way that nodes can communicate with each other. Services allow nodes to send a request and receive a response.
Using rosservice
rosservice可以把services轻松附加到ROS的客户端/服务框架。rosservice有许多可用于主题的命令,如下所示:
用法:
rosservice list print information about active services
rosservice call call the service with the provided args
rosservice type print service type
rosservice find find services by service type
rosservice uri print service ROSRPC uri
rosservice list
$ rosservice list
The list command shows us that the turtlesim node provides nine services
rosservice type
rosservice type [service]
Let’s find out what type the clear service is:
$ rosservice type /clear
结果:
std_srvs/Empty
This service is empty, this means when the service call is made it takes no arguments
rosservice call
用法:
rosservice call [service] [args]
Here we’ll call with no arguments because the service is of type empty:
$ rosservice call /clear
This does what we expect, it clears the background of the turtlesim_node.
Let’s look at the case where the service has arguments by looking at the information for the service spawn:
$ rosservice type /spawn | rossrv show
结果:
float32 x
float32 y
float32 theta
string name
---
string name
这项服务让我们在给定的位置和方向产生一只新的乌龟。name字段是可选的,所以我们不要给我们的新龟命名,让turtlesim为我们创建一个。
$ rosservice call / spawn 2 2 0.2“”
使用rosparam
rosparam allows you to store and manipulate data on the ROS Parameter Server,rosparam uses the YAML markup language for syntax.
用法:
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
rosparam list
Let’s look at what parameters are currently on the param server:
$ rosparam list
rosparam set and rosparam get
用法:
rosparam set [param_name]
rosparam get [param_name]
Here will change the red channel of the background color:
$ rosparam set /background_r 150
Now let’s look at the values of other parameters on the param server. Let’s get the value of the green background channel:
$ rosparam get /background_g
结果:
86
We can also use rosparam get / to show us the contents of the entire Parameter Server.
$ rosparam get /
结果:
background_b: 255
background_g: 86
background_r: 150
roslaunch:
uris: {'aqy:51932': 'http://aqy:51932/'}
run_id: e07ea71e-98df-11de-8875-001b21201aa8
rosparam dump and rosparam load
用法:
rosparam dump [file_name] [namespace]
rosparam load [file_name] [namespace]
Here we write all the parameters to the file params.yaml
$ rosparam dump params.yaml
这里的文件好像保存到当前文件夹
You can even load these yaml files into new namespaces, e.g. copy:
$ rosparam load params.yaml copy
$ rosparam get /copy/background_b
结果:
255
#8.Using rqt_console and roslaunch
说明:本教程使用ROS介绍rqt_console和rqt_logger_level用于调试以及使用roslaunch在一次启动多个节点
Prerequisites rqt and turtlesim package
$ sudo apt-get install ros--rqt ros--rqt-common-plugins ros--turtlesim
Replace
with the name of your ROS distribution (e.g. indigo, jade, kinetic
, lunar…).
Using rqt_console and rqt_logger_level
rqt_console attaches to ROS’s logging framework to display output from nodes. rqt_logger_level allows us to change the verbosity level (DEBUG, WARN, INFO, and ERROR) of nodes as they run.
$ rosrun rqt_console rqt_console
$ rosrun rqt_logger_level rqt_logger_level
Now let’s start turtlesim in a new terminal:
$ rosrun turtlesim turtlesim_node
Quick Note about logger levels
Fatal
Error
Warn
Info
Debug
Using roslaunch
roslaunch starts nodes as defined in a launch file.
用法:
$ roslaunch [package] [filename.launch]
$ cd ~/catkin_ws
$ source devel/setup.bash
$ roscd beginner_tutorials
Then let’s make a launch directory:
$ mkdir launch
$ cd launch
注意:存储启动文件的目录不一定必须命名为launch。实际上,您甚至不需要将它们存储在目录中。roslaunch命令自动查看传递的包并检测可用的启动文件。但是,这被认为是一种很好的做法。
The Launch File
切换行号显示
roslaunching
Now let’s roslaunch the launch file:
$ roslaunch beginner_tutorials turtlemimic.launch
$ rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]'
You will see the two turtlesims start moving even though the publish command is only being sent to turtlesim1.
#9.Using rosed to edit files in ROS
Using rosed
用法:
$ rosed [package_name] [filename]
例如:
$ rosed roscpp Logger.msg
Using rosed with tab completion
用法:
$ rosed [package_name]
例如:
$ rosed roscpp
Empty.srv package.xml
GetLoggers.srv roscpp-msg-extras.cmake
Logger.msg roscpp-msg-paths.cmake
SetLoggerLevel.srv roscpp.cmake
genmsg_cpp.py roscppConfig-version.cmake
gensrv_cpp.py roscppConfig.cmake
msg_gen.py
Editor
The default editor for rosed is vim
. The more beginner-friendly editor nano
is included with the default Ubuntu install. You can use it by editing your ~/.bashrc
file to include:
export EDITOR='nano -w'
Open a new terminal and see if EDITOR is defined:
$ echo $EDITOR
结果:
nano -w
#10.Creating a ROS msg and srv
本节主要讲述了如何创建和建立ROS msg和srv,同时使用命令行工具rosmsg、rossrv和roscp。
Introduction to msg and srv
int8, int16, int32, int64 (plus uint*)
float32, float64
string
time, duration
other msg files
variable-length array[] and fixed-length array[C]
Here is an example of a msg that uses a Header, a string primitive, and two other msgs :
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
srv files are just like msg files, except they contain two parts: a request and a response. The two parts are separated by a ‘—’ line. Here is an example of a srv file:
int64 A
int64 B
---
int64 Sum
In the above example, A and B are the request, and Sum is the response.
Using msg
Creating a msg
Let’s define a new msg in the package that was created in the previous tutorial.
$ roscd beginner_tutorials
$ mkdir msg
$ echo "int64 num" > msg/Num.msg
不过还有一个步骤。我们需要确保将msg文件转换为C ++,Python和其他语言的源代码:
打开package.xml,确保这两行都在其中并取消注释
message_generation build_depend>
message_runtime exec_depend>
at build time, we need "message_generation"
, while at runtime, we only need "message_runtime"
.
Open CMakeLists.txt
in your favorite text editor (rosed
from the previous tutorial is a good option).
在 CMakeLists.txt文件中,利用find_packag函数,增加对message_generation的依赖,这样就可以生成消息了。 你可以直接在COMPONENTS的列表里增加message_generation,就像这样:
# Do not just add this to your CMakeLists.txt, modify the existing text to add message_generation before the closing parenthesis
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
有时候你会发现,即使你没有调用find_package,你也可以编译通过。这是因为catkin把你所有的package都整合在一起,因此,如果其他的package调用了find_package,你的package的依赖就会是同样的配置。但是,在你单独编译时,忘记调用find_package会很容易出错。
Also make sure you export the message runtime dependency.
catkin_package(
...
CATKIN_DEPENDS message_runtime ...
...)
Find the following block of code:
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
Uncomment it by removing the # symbols and then replace the stand in Message*.msg files with your .msg file, such that it looks like this:
add_message_files(
FILES
Num.msg
)
By adding the .msg files manually, we make sure that CMake knows when it has to reconfigure the project after you add other .msg files.
Now we must ensure the generate_messages() function is called.
# generate_messages(
# DEPENDENCIES
# std_msgs
# )
so it looks like:
generate_messages(
DEPENDENCIES
std_msgs
)
Using rosmsg
That’s all you need to do to create a msg. Let’s make sure that ROS can see it using the rosmsg show command.
用法:
$ rosmsg show [message type]
例如:
$ rosmsg show beginner_tutorials/Num
int64 num
In the previous example, the message type consists of two parts:
If you can’t remember which Package a msg is in, you can leave out the package name. Try:
$ rosmsg show Num
You will see:
[beginner_tutorials/Num]:
int64 num
Using srv
Creating a srv
Let’s use the package we just created to create a srv:
$ roscd beginner_tutorials
$ mkdir srv
Instead of creating a new srv definition by hand, we will copy an existing one from another package.
For that, roscp is a useful commandline tool for copying files from one package to another.
用法:
$ roscp [package_name] [file_to_copy_path] [copy_path]
Now we can copy a service from the rospy_tutorials package:
$ roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv
There’s one more step, though. We need to make sure that the srv files are turned into source code for C++, Python, and other languages.
Unless you have done so already, open package.xml, and make sure these two lines are in it and uncommented:
message_generation
message_runtime
As before, note that at build time, we need “message_generation”, while at runtime, we only need “message_runtime”.
Unless you have done so already for messages in the previous step, add the message_generation dependency to generate messages in CMakeLists.txt:
# Do not just add this line to your CMakeLists.txt, modify the existing line
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
(Despite its name, message_generation works for both msg and srv.)
Also you need the same changes to package.xml for services as for messages, so look above for the additional dependencies required.
Remove # to uncomment the following lines:
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
Using rossrv
That’s all you need to do to create a srv. Let’s make sure that ROS can see it using therossrv show
command.
用法:
$ rossrv show
例如:
$ rossrv show beginner_tutorials/AddTwoInts
You will see:
int64 a
int64 b
---
int64 sum
Similar to rosmsg, you can find service files like this without specifying package name:
$ rossrv show AddTwoInts
[beginner_tutorials/AddTwoInts]:
int64 a
int64 b
---
int64 sum
[rospy_tutorials/AddTwoInts]:
int64 a
int64 b
---
int64 sum
Common step for msg and srv
Unless you have already done this in the previous steps, change in CMakeLists.txt. :
# generate_messages(
# DEPENDENCIES
# # std_msgs # Or other packages containing msgs
# )
Uncomment it and add any packages you depend on which contain .msg files that your messages use (in this case std_msgs
), such that it looks like this:
generate_messages(
DEPENDENCIES
std_msgs
)
Now that we have made some new messages we need to make our package again:
# In your catkin workspace
$ roscd beginner_tutorials
$ cd ../..
$ catkin_make install
$ cd -
Any .msg file in the msg directory will generate code for use in all supported languages. The C++ message header file will be generated in
~/catkin_ws/devel/include/beginner_tutorials/
.
The Python script will be created in
~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg
.
The lisp file appears in~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/
.
Similarly, any .srv files in the srv directory will have generated code in supported languages. For C++, this will generate header files in the same directory as the message header files. For Python and Lisp, there will be an ‘srv’ folder beside the ‘msg’ folders.
If you are building C++ nodes which use your new messages, you will also need to declare a dependency between your node and your message, as described in the catkin msg/srv build documentation.
Getting Help
We’ve seen quite a few ROS tools already. It can be difficult to keep track of what arguments each command requires. Luckily, most ROS tools provide their own help.
$ rosmsg -h
You should see a list of different rosmsg subcommands
Commands:
rosmsg show Show message description
rosmsg list List all messages
rosmsg md5 Display message md5sum
rosmsg package List messages in a package
rosmsg packages List packages that contain messages
You can also get help for subcommands
$ rosmsg show -h
This shows the arguments that are needed for rosmsg show:
Usage: rosmsg show [options]
Options:
-h, --help show this help message and exit
-r, --raw show raw message text, including comments
Review
Let’s just list some of the commands we’ve used so far:
Writing the Publisher Node
“Node” is the ROS term for an executable that is connected to the ROS network. Here we’ll create a publisher (“talker”) node which will continually broadcast a message.
roscd beginner_tutorials
The Code
Create a src directory in the beginner_tutorials package directory:
mkdir -p src
This directory will contain any source files
for our beginner_tutorials package.
Create the src/talker.cpp
file within the beginner_tutorials package and paste the following inside it:
#include "ros/ros.h"
#include "std_msgs/String.h"
#include
/**
* This tutorial demonstrates simple sending of messages over the ROS system.
*/
int main(int argc, char **argv)
{
/**
* The ros::init() function needs to see argc and argv so that it can perform
* any ROS arguments and name remapping that were provided at the command line.
* For programmatic remappings you can use a different version of init() which takes
* remappings directly, but for most command-line programs, passing argc and argv is
* the easiest way to do it. The third argument to init() is the name of the node.
*
* You must call one of the versions of ros::init() before using any other
* part of the ROS system.
*/
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.
*
* The second parameter to advertise() is the size of the message queue
* used for publishing messages. If messages are published more quickly
* than we can send them, the number here specifies how many messages to
* buffer up before throwing some away.
*/
ros::Publisher chatter_pub = n.advertise("chatter", 1000);
ros::Rate loop_rate(10);
/**
* A count of how many messages we have sent. This is used to create
* a unique string for each message.
*/
int count = 0;
while (ros::ok())
{
/**
* This is a message object. You stuff it with data, and then publish it.
*/
std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
ROS_INFO("%s", msg.data.c_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.
*/
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
return 0;
}
The Code Explained
Now, let’s break the code down.(代码分析)
#include "ros/ros.h"
ros/ros.h is a convenience include that includes all the headers necessary to use the most common public pieces of the ROS system.
#include "std_msgs/String.h"
This includes the std_msgs/String message, which resides in the std_msgs package. This is a header generated automatically from the String.msg file in that package. For more information on message definitions, see the msg page.
ros::init(argc, argv, "talker");
Initialize ROS
. This allows ROS to do name remapping through the command line – not important for now. This is also wspecify the name
of our node. Node names must be unique
in a running system.
ros::NodeHandle n;
Create a handle to this process’ node. The first NodeHandle created will actually do the initialization of the node, and the last one destructed will cleanup any resources the node was using.
ros::Publisher chatter_pub = n.advertise("chatter", 1000);
Tell the master that we are going to be publishing a message of type std_msgs/String
on the topic chatter. This lets the master tell any nodes listening on chatter that we are going to publish data on that topic. The second argument
is the size of our publishing queue. In this case if we are publishing too quickly it will buffer up a maximum of 1000 messages before beginning to throw away old ones.
NodeHandle::advertise()
returns a ros::Publisher
object, which serves two purposes: 1) it contains a publish() method that lets you publish messages onto the topic it was created with, and 2) when it goes out of scope, it will automatically unadvertise.
ros::Rate loop_rate(10);
A ros::Rate
object allows you to specify a frequency that you would like to loop at. It will keep track of how long it has been since the last call to Rate::sleep()
, and sleep for the correct amount of time.
In this case we tell it we want to run at 10Hz.
int count = 0;
while (ros::ok())
{
By default roscpp will install a SIGINT
handler which provides Ctrl-C
handling which will cause ros::ok()
to return false if that happens.
ros::ok()
will return false if:
ros::ok()
returns false, all ROS calls will fail. std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
We broadcast a message on ROS using a message-adapted class, generally generated from a msg file. More complicated datatypes are possible, but for now we’re going to use the standard String message, which has one member: “data”.
chatter_pub.publish(msg);
Now we actually broadcast the message to anyone who is connected.
ROS_INFO("%s", msg.data.c_str());
ROS_INFO and friends are our replacement for printf/cout
. See the rosconsole documentation for more information.
ros::spinOnce();
Calling ros::spinOnce()
here is not necessary for this simple program, because we are not receiving any callbacks. However, if you were to add a subscription into this application, and did not have ros::spinOnce() here, your callbacks would never get called. So, add it for good measure.
loop_rate.sleep();
Now we use the ros::Rate
object to sleep for the time remaining to let us hit our 10Hz publish rate.
Here’s the condensed version(简缩) of what’s going on:(总结)
src/listener.cpp
file within the beginner_tutorials package and paste the following inside it:#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)
{
/**
* The ros::init() function needs to see argc and argv so that it can perform
* any ROS arguments and name remapping that were provided at the command line.
* For programmatic remappings you can use a different version of init() which takes
* remappings directly, but for most command-line programs, passing argc and argv is
* the easiest way to do it. The third argument to init() is the name of the node.
*
* You must call one of the versions of ros::init() before using any other
* part of the ROS system.
*/
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.
*/
ros::spin();
return 0;
}
The Code Explained
Now, let’s break it down piece by piece, ignoring some pieces that have already been explained above.
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
This is the callback function that will get called when a new message has arrived on the chatter topic. The message is passed in a boost shared_ptr, which means you can store it off if you want, without worrying about it getting deleted underneath you, and without copying the underlying data.
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
Subscribe to the chatter topic with the master. ROS will call the chatterCallback()
function whenever a new message arrives. The 2nd argument is the queue size, in case we are not able to process messages fast enough. In this case, if the queue reaches 1000 messages, we will start throwing away old messages as new ones arrive.
NodeHandle::subscribe()
returns a ros::Subscriber object, that you must hold on to until you want to unsubscribe. When the Subscriber object is destructed, it will automatically unsubscribe from the chatter topic.
There are versions of the NodeHandle::subscribe() function which allow you to specify a class member function, or even anything callable by a Boost.Function object. The roscpp overview contains more information.
ros::spin();
ros::spin()
enters a loop, calling message callbacks as fast as possible. Don’t worry though, if there’s nothing for it to do it won’t use much CPU. ros::spin() will exit once ros::ok() returns false, which means ros::shutdown() has been called, either by the default Ctrl-C handler, the master telling us to shutdown, or it being called manually.
There are other ways of pumping callbacks, but we won’t worry about those here. The roscpp_tutorials package has some demo applications which demonstrate this. The roscpp overview also contains more information.
Again, here’s a condensed version of what’s going on:
Initialize the ROS system
Subscribe to the chatter topic
Spin, waiting for messages to arrive
When a message arrives, the chatterCallback() function is called
Building your nodes
You used catkin_create_pkg
in a previous tutorial which created a package.xml
and a CMakeLists.txt
file for you.
The generated CMakeLists.txt should look like this (with modifications from the Creating Msgs and Srvs tutorial and unused comments and examples removed):
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv)
## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)
## Declare a catkin package
catkin_package()
Don’t worry about modifying the commented (#) examples, simply add these few lines to the bottom of your CMakeLists.txt:
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)
Your resulting CMakeLists.txt file should look like this:
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
## Declare ROS messages and services
add_message_files(FILES Num.msg)
add_service_files(FILES AddTwoInts.srv)
## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)
## Declare a catkin package
catkin_package()
## Build talker and listener
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)
This will create two executables, talker and listener, which by default will go into package directory of your devel space, located by default at ~/catkin_ws/devel/lib/
Note that you have to add dependencies for the executable targets to message generation targets:
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
This makes sure message headers of this package are generated before being used. If you use messages from other packages inside your catkin workspace, you need to add dependencies to their respective generation targets as well, because catkin builds all projects in parallel. As of Groovy you can use the following variable to depend on all necessary targets:
target_link_libraries(talker ${catkin_LIBRARIES})
You can invoke executables directly or you can use rosrun to invoke them. They are not placed in ‘< prefix >/bin’ because that would pollute the PATH when installing your package to the system. If you wish for your executable to be on the PATH at installation time, you can setup an install target, see: catkin/CMakeLists.txt
For more detailed discription of the CMakeLists.txt file see: catkin/CMakeLists.txt
Now run catkin_make:
# In your catkin workspace
$ cd ~/catkin_ws
$ catkin_make
Note: Or if you’re adding as new pkg, you may need to tell catkin to force making by --force-cmake option. See catkin/Tutorials/using_a_workspace#With_catkin_make.
Now that you have written a simple publisher and subscriber, let’s examine the simple publisher and subscriber.
Description: This tutorial covers how to write a service and client node in C++
##1.Writing a Service Node
Here we’ll create the service (“add_two_ints_server”) node which will receive two ints and return the sum.
Change directories to your beginner_tutorials package you created in your catkin workspace previous tutorials:
roscd beginner_tutorials
Please make sure you have followed the directions in the previous tutorial for creating the service needed in this tutorial, creating the AddTwoInts.srv (be sure to choose the right version of build tool you’re using at the top of wiki page in the link).
1.1The Code
Create the src/add_two_ints_server.cpp file within the beginner_tutorials package and paste the following inside it:
#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.");
ros::spin();
return 0;
}
1.2 The Code Explained
Now, let’s break the code down.
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
beginner_tutorials/AddTwoInts.h
is the header file generated from the srv file that we created earlier.
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
This function provides the service for adding two ints, it takes in the request and response type defined in the srv file and returns a boolean.
{
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;
}
Here the two ints are added and stored in the response. Then some information about the request and response are logged. Finally the service returns true when it is complete.
ros::ServiceServer service = n.advertiseService("add_two_ints", add);
Here the service is created and advertised over ROS.
##2.Writing the Client Node
####2.1 The Code
Create the src/add_two_ints_client.cpp
file within the beginner_tutorials package and paste the following inside it:
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include
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("add_two_ints");
beginner_tutorials::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_two_ints");
return 1;
}
return 0;
}
Now, let’s break the code down.
ros::ServiceClient client = n.serviceClient("add_two_ints");
This creates a client for the add_two_ints service. The ros::ServiceClient object is used to call the service later on.
beginner_tutorials::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
Here we instantiate(实例化) an autogenerated(自动生成) service class, and assign(分配) values into its request member. A service class contains two members, request and response. It also contains two class definitions, Request and Response.
if (client.call(srv))
This actually calls the service. Since service calls are blocking, it will return once the call is done. If the service call succeeded, call() will return true and the value in srv.response will be valid. If the call did not succeed, call() will return false and the value in srv.response will be invalid.
Again edit the beginner_tutorials CMakeLists.txt located at ~/catkin_ws/src/beginner_tutorials/CMakeLists.txt
and add the following at the end:
https://raw.github.com/ros/catkin_tutorials/master/create_package_srvclient/catkin_ws/src/beginner_tutorials/CMakeLists.txt
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)
This will create two executables, add_two_ints_server
and add_two_ints_client
, which by default will go into package directory of your devel space, located by default at ~/catkin_ws/devel/lib/< package name>
. You can invoke executables directly or you can use rosrun to invoke them. They are not placed in ‘< prefix>/bin’ because that would pollute the PATH when installing your package to the system. If you wish for your executable to be on the PATH at installation time, you can setup an install target, see: catkin/CMakeLists.txt
For more detailed description of the CMakeLists.txt file see: catkin/CMakeLists.txt
Now run catkin_make:
# In your catkin workspace
cd ~/catkin_ws
catkin_make
If your build fails for some reason:
make sure you have followed the directions in the previous tutorial: creating the AddTwoInts.srv.
Running nodes requires you have a ROS core started. Open a new shell, and type:
roscore
If all goes well, you should see an output that looks something like this:
... logging to /u/takayama/.ros/logs/83871c9c-934b-11de-a451-
001d927076eb/roslaunch-ads-31831.log
... loading XML file
[/wg/stor1a/rosbuild/shared_installation/ros/tools/roslaunch/roscore.xml]
Added core node of type [rosout/rosout] in namespace [/]
started roslaunch server http://ads:54367/
SUMMARY
======
NODES
changing ROS_MASTER_URI to [http://ads:11311/] for starting master locally
starting new master (master configured for auto start)
process[master]: started with pid [31874]
ROS_MASTER_URI=http://ads:11311/
setting /run_id to 83871c9c-934b-11de-a451-001d927076eb
+PARAM [/run_id] by /roslaunch
+PARAM [/roslaunch/uris/ads:54367] by /roslaunch
process[rosout-1]: started with pid [31889]
started core service [/rosout]
+SUB [/time] /rosout http://ads:33744/
+SERVICE [/rosout/get_loggers] /rosout http://ads:33744/
+SERVICE [/rosout/set_logger_level] /rosout http://ads:33744/
+PUB [/rosout_agg] /rosout http://ads:33744/
+SUB [/rosout] /rosout http://ads:33744/
Now everything is set to run server and client.
Start by running the server. Open a new shell and type:
source ~/catkin_ws2/devel/setup.bash
rosrun beginner_tutorials add_two_ints_server
You should see something similar to:
Ready to add two ints.
Now let’s run the client with the necessary arguments, in another shell:
source ~/catkin_ws2/devel/setup.bash
$ rosrun beginner_tutorials add_two_ints_client 1 3
In the client’s shell, you should see something similar to:
Sum: 4
In the server’s shell, instead, you should see something similar to:
request: x=1, y=3
sending back response: [4]
Now that you have written a simple service and client, let’s examine the simple service and client.
Description: This tutorial examines running the simple service and client
##1.Running the Service
Let’s start by running the service:
$ rosrun beginner_tutorials add_two_ints_server (C++)
$ rosrun beginner_tutorials add_two_ints_server.py (Python)
You should see something similar to:
Ready to add two ints.
Now let’s run the client with the necessary arguments:
$ rosrun beginner_tutorials add_two_ints_client 1 3 (C++)
$ rosrun beginner_tutorials add_two_ints_client.py 1 3 (Python)
You should see something similar to:
Requesting 1+3
1 + 3 = 4
Now that you’ve successfully run your first server and client, let’s learn how to record and play back data.
If you want to investigate further and get a hands-on example, you can get one here. A simple Client and Service combination shows the use of custom message types. The Service node is written in C++ while the Client is available in C++, Python and LISP.