####################################
##FILL ME IN
####################################
## links to any required tutorials
## note.0= [[cn/ROS/Tutorials/UsingRosEd|使用rosed]]
## descriptive title for the tutorial
## title = 创建ROS消息和服务
## multi-line description to be displayed in search
## description = 本教程介绍如何创建和构建msg和srv文件,以及[[rosmsg]]、rossrv和roscp命令行工具的使用。
## the next tutorial description (optional)
## next = 编写简单的发布者和订阅者
## links to next tutorial (optional)
## next.0.link= [[cn/ROS/Tutorials/WritingPublisherSubscriber(python)|(Python)]]
## next.1.link= [[cn/ROS/Tutorials/WritingPublisherSubscriber(c++)|(C++)]]
## what level user is this tutorial for
## level= BeginnerCategory
####################################
<<IncludeCSTemplate(TutorialCSHeaderTemplate)>>

<<Buildsystem()>>

<<TOC(4)>>
##startintro
== msg和srv介绍 ==
 * [[msg]](消息):msg文件就是文本文件,用于描述ROS消息的字段。它们用于为不同编程语言编写的消息生成源代码。
 * [[srv]](服务):一个srv文件描述一个服务。它由两部分组成:请求(request)和响应(response)。
##endintro
msg文件存放在软件包的`msg`目录下,srv文件则存放在`srv`目录下。
##startsyntax
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}}}是响应。
##endsyntax
== 使用msg ==
=== 创建msg ===
下面,我们将在之前创建的软件包里定义一个新的消息。

{{{{#!wiki buildsystem catkin
{{{
$ 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`, 确保它包含以下两行且没有被[[http://www.htmlhelp.com/reference/wilbur/misc/comment.html|注释]]。如果没有,添加进去:
{{{
  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
}}}

注意,在构建时,其实只需要`message_generation`,而在运行时,我们只需要`message_runtime`。

在你喜欢的文本编辑器中打开`CMakeLists.txt`文件([[cn/ROS/Tutorials/UsingRosEd|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及早期版本中,'''只需要取消这一行的注释:
{{{
generate_messages()
}}}
}}}}

{{{{#!wiki buildsystem rosbuild
{{{
$ roscd beginner_tutorials
$ mkdir msg
$ echo "int64 num" > msg/Num.msg
}}}

The example above is the simplest, where the `.msg` file contains only 1 line. You can, of course, create more complex files by adding multiple elements per line like this:
{{{
string first_name
string last_name
uint8 age
uint32 score
}}}

There's one more step, though. We need to make sure that the msg files are turned into source code for C++, Python, and other languages. Open `CMakeLists.txt` in your favorite text editor ([[ROS/Tutorials/UsingRosEd|rosed]] from the previous tutorial is a good option) and remove `#` to uncomment the following line:
{{{
# rosbuild_genmsg()
}}}
}}}}
{{{#!wiki buildsystem catkin
现在,你可以从msg文件定义中生成源代码文件了。如果现在就想这样做,请直接跳到[[cn/ROS/Tutorials/CreatingMsgAndSrv#msg.2BVIw-srv.2BdoROAIIsa2WapA-|msg和srv的一般步骤]]。
}}}
=== 使用rosmsg ===
以上就是创建消息的所有步骤。让我们通过`rosmsg show`命令看看ROS能否识别它。

用法:

{{{
$ rosmsg show [message type]
}}}
示例:

{{{
$ rosmsg show beginner_tutorials/Num
}}}
你会看到:

 . {{{
int64 num
}}}

在上面的例子中,消息类型包含两部分:

 * {{{beginner_tutorials}}}  -- 定义消息的软件包
 * {{{Num}}} -- 消息的名称{{{Num}}}

如果不记得msg在哪个包中,也可以省略包名称。尝试:

{{{
$ rosmsg show Num
}}}
你会看到:

 . {{{
[beginner_tutorials/Num]:
int64 num
}}}

== 使用srv ==
=== 创建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和其他语言的源代码。
{{{{#!wiki buildsystem catkin
如果没做过上面的教程,请先打开`package.xml`,确保它包含以下两行且没有被[[http://www.htmlhelp.com/reference/wilbur/misc/comment.html|注释]]。如果没有,添加进去:
{{{
  <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
)
}}}
}}}}

{{{{#!wiki buildsystem rosbuild
Once again, open CMakeLists.txt and remove `#` to uncomment the following line:
{{{
# rosbuild_gensrv()
}}}
}}}}

{{{#!wiki buildsystem catkin
现在,你可以从srv文件定义中生成源代码文件了。如果现在就想这样做,请直接跳到[[cn/ROS/Tutorials/CreatingMsgAndSrv#msg.2BVIw-srv.2BdoROAIIsa2WapA-|msg和srv的一般步骤]]。

}}}

=== 使用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包中已经存在的。

== msg和srv的一般步骤 ==
{{{{#!wiki buildsystem catkin
如果没做过上面的教程,请先修改下`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 -
}}}
}}}}

{{{{#!wiki buildsystem rosbuild
Now that we have made some new messages we need to make our package again:
{{{
$ rosmake beginner_tutorials
}}}
}}}}
`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`目录中。

消息格式的完整规范在[[ROS/Message_Description_Language|消息描述语言]]中。
{{{#!wiki buildsystem catkin
如果你正在构建使用新消息的C++节点,则还需要声明节点和消息之间的依赖关系,参见[[http://docs.ros.org/latest/api/catkin/html/howto/format2/building_msgs.html|catkin消息和服务构建文档]]。
}}}


== 获取帮助 ==


我们已经接触到不少ROS工具了。有时候很难记住每个命令所需要的参数。好在大多数ROS工具都提供了自己的帮助。

尝试:

{{{
$ rosmsg -h
}}}
 . 你可以看到一系列的{{{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 -h
}}}
 . 这会显示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
}}}

== 复习 ==
总结一下到目前为止我们接触过的一些命令:
 * rospack = ros+pack(age) : provides information related to ROS packages
 * roscd = ros+cd  : '''c'''hanges '''d'''irectory to a ROS package or stack
 * rosls = ros+ls  : '''l'''ist'''s''' files in a ROS package
 * roscp = ros+cp  : '''c'''o'''p'''ies 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消息和服务,接下来就将学习如何编写简单的发布者和订阅者[[cn/ROS/Tutorials/WritingPublisherSubscriber(python)|(Python)]][[cn/ROS/Tutorials/WritingPublisherSubscriber(c++)|(C++)]]。

## AUTOGENERATED DO NOT DELETE
## TutorialCategory
## ROSTutorialCategory