Description: 本教程介绍如何创建和构建msg和srv文件,以及rosmsg、rossrv和roscp命令行工具的使用。
                               Tutorial Level: BEGINNER 
                            1 msg和srv介绍 
                                  -  msg(消息):msg文件就是文本文件,用于描述ROS消息的字段。它们用于为不同编程语言编写的消息生成源代码。
                            
  - srv(服务):一个srv文件描述一个服务。它由两部分组成:请求(request)和响应(response)。
   
                              
                                msg文件存放在软件包的msg目录下,srv文件则存放在srv目录下。 
                              msg文件就是简单的文本文件,每行都有一个字段类型和字段名称。可以使用的类型为: 
                             - int8, int16, int32, int64 (以及 uint*)
                                  -  float32, float64
                                  -  string
                                  -  time, duration
                                  -  其他msg文件
                                 -   variable-length array[] 和 fixed-length array[C]
   
                                ROS中还有一个特殊的数据类型:Header,它含有时间戳和ROS中广泛使用的坐标帧信息。在msg文件的第一行经常可以看到Header 
                                header。 
                              下面是一个使用了Header、字符串原语和其他两个消息的示例: 下面是一个msg文件的样例,它使用了Header,string,和其他另外两个消息的类型: 
                             
                            
                                 Header header
  string child_frame_id
  geometry_msgs/PoseWithCovariance pose
  geometry_msgs/TwistWithCovariance twist 
  |   
 
                              
                                srv文件和msg文件一样,只是它们包含两个部分:请求和响应。这两部分用一条---线隔开。下面是一个srv文件的示例: 
                             
                            
                               int64 A
int64 B
---
int64 Sum 
  |   
 
                                在上面的例子中,A和B是请求, Sum是响应。 
                             2 使用msg 
                                 2.1 创建msg 
                                下面,我们将在之前创建的软件包里定义一个新的消息。 
                              
                            
                            
                               $ roscd beginner_tutorials
$ mkdir msg
$ echo "int64 num" > msg/Num.msg 
  |   
                                
                              
                                上面是最简单的示例,.msg文件只有一行。当然,你可以通过添加更多元素(每行一个)来创建一个更复杂的文件,如下所示: 
                             
                            
                               string first_name
string last_name
uint8 age
uint32 score 
  |   
 
                                不过还有关键的一步:我们要确保msg文件能被转换为C++、Python和其他语言的源代码。 
                              打开package.xml, 确保它包含以下两行且没有被注释。如果没有,添加进去: 
                              
                            
                                 <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend> 
  |   
                                
                              
                                注意,在构建时,其实只需要message_generation,而在运行时,我们只需要message_runtime。 
                              在你喜欢的文本编辑器中打开CMakeLists.txt文件(rosed是一个不错的选择)。 
                              在CMakeLists.txt文件中,为已经存在里面的find_package调用添加message_generation依赖项,这样就能生成消息了。直接将message_generation添加到COMPONENTS列表中即可,如下所示: 
                             
                            
                               # 不要直接复制这一大段,只需将message _generation加在括号闭合前即可
find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
) 
  |   
                              你可能注意到了,有时即使没有使用全部依赖项调用find_package,项目也可以构建。这是因为catkin把你所有的项目整合在了一起,因此如果之前的项目调用了find_package,你的依赖关系也被配置成了一样的值。但是,忘记调用意味着你的项目在单独构建时很容易崩溃。 
                              还要确保导出消息的运行时依赖关系: 
                             
                            
                               catkin_package(
  ...
  CATKIN_DEPENDS message_runtime ...
  ...) 
  |   
                                
                              
                                找到如下代码块: 
                            
                            
                               # add_message_files(
#   FILES
#   Message1.msg
#   Message2.msg
# ) 
  |   
                                
                              
                                删除#符号来取消注释,然后将Message*.msg替换为你的.msg文件名,就像下边这样: 
                              
                            
                               
add_message_files(
  FILES
  Num.msg
) 
  |   
                                 
                              
                                手动添加.msg文件后,我们要确保CMake知道何时需要重新配置项目。 
                              现在必须确保generate_messages()函数被调用: 
                              在ROS Hydro及更新版本中,你需要取消下面几行的注释: 
                             
                            
                               # generate_messages(
#   DEPENDENCIES
#   std_msgs
# ) 
  |   
 
                                像这样: 
                            
                               generate_messages(
  DEPENDENCIES
  std_msgs
) 
  |   
                                 
                              
                                在ROS Groovy及早期版本中,只需要取消这一行的注释: 
                             
                                
                              
                                现在,你可以从msg文件定义中生成源代码文件了。如果现在就想这样做,请直接跳到msg和srv的一般步骤。 
                               2.2 使用rosmsg 
                                以上就是创建消息的所有步骤。让我们通过rosmsg show命令看看ROS能否识别它。 
                              用法: 
                             
                            
                               $ rosmsg show [message type] 
  |   
 
                              
                                示例: 
                             
                            
                               $ rosmsg show beginner_tutorials/Num 
  |   
 
                              
                                你会看到: 
                             
 
                                在上面的例子中,消息类型包含两部分: 
                               - beginner_tutorials -- 定义消息的软件包
                            
  - Num -- 消息的名称Num
   
                              如果不记得msg在哪个包中,也可以省略包名称。尝试: 
                             
 
                                你会看到: 
                            
                            
                               
[beginner_tutorials/Num]:
int64 num 
  |   
 
                                  3 使用srv 
                                   3.1 创建srv 
                                让我们使用之前创建的包再来创建服务: 
                              
                            
                               $ roscd beginner_tutorials
$ mkdir srv 
  |   
                              
                              
                                我们将从另一个包复制现有的srv定义,而不是手动创建新的srv。roscp是一个实用的命令行工具,用于将文件从一个包复制到另一个包。 
                              用法: 
                             
                            
                               $ roscp [package_name]  [file_to_copy_path] [copy_path] 
  |   
 
                              
                                现在我们可以从rospy_tutorials包中复制一个服务: 
                              
                            
                                  
 $ roscp rospy_tutorials  AddTwoInts.srv srv/AddTwoInts.srv 
  |   
                                还有关键的一步:我们要确保msg文件能被转换为C++、Python和其他语言的源代码。 
                              如果没做过上面的教程,请先打开package.xml,确保它包含以下两行且没有被注释。如果没有,添加进去: 
                            
                            
                                 <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend> 
  |   
                                
                              
                                如前所述,在构建时,其实只需要message_generation,而在运行时,我们只需要message_runtime。 
                              如果没做过上面的教程,在CMakeLists.txt文件中,为已经存在里面的find_package调用添加message_generation依赖项,这样就能生成消息了。直接将message_generation添加到COMPONENTS列表中即可,如下所示: 
                             
                            
                               # 不要直接复制这一大段, 只需将message_generation加在括号闭合前即可
find_package(catkin REQUIRED COMPONENTS
   roscpp
   rospy
   std_msgs
   message_generation
) 
  |   
                              (别被名字迷惑,message_generation对msg和srv都适用) 
                              此外,你也需要像之前对消息那样在package.xml中修改服务字段,因此请看上面描述的所需附加依赖项。 
                            
                            
                               # add_service_files(
#   FILES
#   Service1.srv
#   Service2.srv
# ) 
  |   
  
                              
                                删除#符号来取消注释,然后将Service*.srv替换为你的.srv文件名,就像下边这样: 
                             
                            
                               add_service_files(
  FILES
  AddTwoInts.srv
) 
  |   
                              现在,你可以从srv文件定义中生成源代码文件了。如果现在就想这样做,请直接跳到msg和srv的一般步骤。 
                              3.2 使用rossrv 
                                以上就是创建服务的所有步骤。让我们通过rossrv show命令看看ROS能否识别它。 
                              用法: 
                            
                            
                               $ rossrv show <service type> 
  |   
  
                              
                                示例: 
                             
                            
                              $ rossrv show beginner_tutorials/AddTwoInts  
 |   
 
                              
                                你会看到: 
                             
                            
                               int64 a
int64 b
---
int64 sum 
  |   
                                
                              
                                跟rosmsg类似, 你也可以在不指定包名的情况下找到这样的服务: 
                            
                            
                               $ rossrv show AddTwoInts
[beginner_tutorials/AddTwoInts]:
int64 a
int64 b
---
int64 sum
[rospy_tutorials/AddTwoInts]:
int64 a
int64 b
---
int64 sum 
  |   
                              
                              
                                这里显示了两个服务。第一个是刚刚在beginner_tutorials包中创建的,第二个是之前rospy_tutorials包中已经存在的。 
                              4 msg和srv的一般步骤 
                              如果没做过上面的教程,请先修改下CMakeLists.txt: 
                             
                            
                               # generate_messages(
#   DEPENDENCIES
# #  std_msgs  # Or other packages containing msgs
# ) 
  |   
                                
                              
                                取消注释,然后添加任意你的消息用到的包含.msg文件的软件包(本例中为std_msgs),如下所示: 
                             
                            
                               generate_messages(
  DEPENDENCIES
  std_msgs
) 
  |   
                                
                              
                                现在我们已经创建了一些新消息,所以需要重新make一下软件包: 
                            
                            
                               # In your catkin workspace
$ roscd beginner_tutorials
$ cd ../..
$ catkin_make
$ cd - 
  |   
                                
                              msg目录中的任何.msg文件都将生成所有支持语言的代码。C++消息的头文件将生成在~/catkin_ws/devel/include/beginner_tutorials/。Python脚本将创建在~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg。而Lisp文件则出现在~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/。 
                              类似地,srv目录中的任何.srv文件都将生成支持语言的代码。对于C++,头文件将生成在消息的头文件的同一目录中。对于Python和Lisp,会在msg目录旁边的srv目录中。 
                              消息格式的完整规范在消息描述语言中。 
                              如果你正在构建使用新消息的C++节点,则还需要声明节点和消息之间的依赖关系,参见catkin消息和服务构建文档。 
                               5 获取帮助 
                                我们已经接触到不少ROS工具了。有时候很难记住每个命令所需要的参数。好在大多数ROS工具都提供了自己的帮助。 
                              尝试: 
                            
  
                                你可以看到一系列的rosmsg子命令。 
                             
                            
                               
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 
  |   
                                
                              
                                同样也可以获得子命令的帮助: 
                             
 
                              
                                这会显示rosmsg show所需的参数: 
                            
                               
Usage: rosmsg show [options] <message type>
Options:
  -h, --help  show this help message and exit
  -r, --raw   show raw  message text, including comments 
  |   
                                 
                              6 复习 
                                总结一下到目前为止我们接触过的一些命令: 
                              - rospack = ros+pack(age) : provides information 
                                related to ROS packages
                                 -   roscd = ros+cd : changes directory to a ROS package 
                                or stack
                            
  - rosls = ros+ls : lists files in a ROS package
                             
  - roscp = ros+cp : copies files from/to a ROS package
                            
  - rosmsg = ros+msg : provides information related 
                                to ROS message definitions
                                  -  rossrv = ros+srv : provides information related 
                                to ROS service definitions
                                   - catkin_make : makes (compiles) a ROS package
                                   - rosmake = ros+make : makes (compiles) a ROS package 
                                (if you're not using a catkin workspace)
   
                                现在已经学习了如何创建ROS消息和服务,接下来就将学习如何编写简单的发布者和订阅者(Python)(C++)。 
                                
                                                             |