使用rosed在ROS中编辑文件
使用rosed
rosed是rosbash套件的一部分。利用它可以直接通过软件包名编辑包中的文件,而无需键入完整路径。
用法:
$ rosed [package_name] [filename]
示例:
$ rosed roscpp Logger.msg
这个例子演示了如何编辑roscpp软件包中的Logger.msg文件。
如果该实例没有运行成功,可能是因为你没有安装vim编辑器。请参考编辑器部分进行设置。
如果你不知道怎么退出vim,请尝试按下键盘上的Esc,然后分别按下:q!。
如果文件名在包中不是唯一的,则菜单将提示你选择要编辑哪个文件。
Tab补全
使用这个方法,在不知道准确文件名的情况下,你也可以轻松地查看和编辑包中的所有文件。
用法:
$ rosed [package_name] <tab><tab>
示例:
$ rosed roscpp <tab><tab>
- 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
编辑器
rosed默认的编辑器是vim。其实Ubuntu默认还有一个初学者更友好的编辑器nano,你可以把下面这行加到~/.bashrc文件中来更改默认编辑器:
export EDITOR='nano -w'
而如果想将默认编辑器设置为emacs,可以进行同样的操作:
export EDITOR='emacs -nw'
注意: .bashrc文件的改变只对新打开的终端有效。之前已经打开的终端不受更改环境变量的影响。
打开一个新的终端,看看是否定义了EDITOR变量:
$ echo $EDITOR
- nano -w
or
emacs -nw
现在你已经成功配置和使用了rosed
创建ROS消息和服务
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是响应。
使用msg
创建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及早期版本中,只需要取消这一行的注释:
generate_messages()
现在,你可以从msg文件定义中生成源代码文件了。如果现在就想这样做,请直接跳到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和其他语言的源代码。
如果没做过上面的教程,请先打开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的一般步骤。
使用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的一般步骤
如果没做过上面的教程,请先修改下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消息和服务构建文档。
获取帮助
我们已经接触到不少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 : 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)
编写发布者节点
“节点”是连接到ROS网络的可执行文件。在这里,我们将创建talker(发布者)节点,该节点将不断广播消息。
将目录切换到之前的教程中创建的beginner_tutorials包中:
$ roscd beginner_tutorials
代码
首先让我们创建一个scripts目录来存放我们的Python脚本:
$ mkdir scripts
$ cd scripts
然后下载示例脚本talker.py放到scripts目录中并给执行权限:
$ wget https://raw.github.com/ros/ros_tutorials/noetic-devel/rospy_tutorials/001_talker_listener/talker.py # 若遇到网络问题,请打开上面文件的链接并复制文本内容到talker.py文件中
$ chmod +x talker.py
先不要运行它。你可以通过下面的命令查看和编辑这个文件。
$ rosed beginner_tutorials talker.py
- 切换行号显示
- 1 #!/usr/bin/env python
- 2 # license removed for brevity
- 3 import rospy
- 4 from std_msgs.msg import String
- 5
- 6 def talker():
- 7 pub = rospy.Publisher('chatter', String, queue_size=10)
- 8 rospy.init_node('talker', anonymous=True)
- 9 rate = rospy.Rate(10) # 10hz
- 10 while not rospy.is_shutdown():
- 11 hello_str = "hello world %s" % rospy.get_time()
- 12 rospy.loginfo(hello_str)
- 13 pub.publish(hello_str)
- 14 rate.sleep()
- 15
- 16 if __name__ == '__main__':
- 17 try:
- 18 talker()
- 19 except rospy.ROSInterruptException:
- 20 pass
然后将以下内容添加到CMakeLists.txt文件。这样可以确保正确安装Python脚本,并使用合适的Python解释器。
catkin_install_python(PROGRAMS scripts/talker.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
解释
现在,让我们把代码分解。
1 #!/usr/bin/env python
每个Python ROS节点的最开头都有这个声明。第一行确保脚本作为Python脚本执行。
3 import rospy
4 from std_msgs.msg import String
如果要编写ROS节点,则需要导入rospy。std_msgs.msg的导入则是为了使我们能够重用std_msgs/String消息类型(即一个简单的字符串容器)来发布。
7 pub = rospy.Publisher('chatter', String, queue_size=10)
8 rospy.init_node('talker', anonymous=True)
这部分代码定义了talker与其他ROS部分的接口。pub = rospy.Publisher("chatter", String, queue_size=10)声明该节点正在使用String消息类型发布到chatter话题。这里的String实际上是std_msgs.msg.String类。queue_size参数是在ROS Hydro及更新版本中新增的,用于在订阅者接收消息的速度不够快的情况下,限制排队的消息数量。对于ROS Groovy及早期版本来说,只需省略即可。
下一行的rospy.init_node(NAME, ...)非常重要,因为它把该节点的名称告诉了rospy——只有rospy掌握了这一信息后,才会开始与ROS主节点进行通信。在本例中,你的节点将使用talker名称。注意:名称必须是基本名称,例如不能包含任何斜杠/。
anonymous = True会让名称末尾添加随机数,来确保节点具有唯一的名称。请参考从启动到关机——初始化ROS节点。
9 rate = rospy.Rate(10) # 10hz
此行创建一个Rate对象rate。借助其方法sleep(),它提供了一种方便的方法,来以你想要的速率循环。它的参数是10,即表示希望它每秒循环10次(只要我们的处理时间不超过十分之一秒)!
10 while not rospy.is_shutdown():
11 hello_str = "hello world %s" % rospy.get_time()
12 rospy.loginfo(hello_str)
13 pub.publish(hello_str)
14 rate.sleep()
这个循环是一个相当标准的rospy结构:检查rospy.is_shutdown()标志,然后执行代码逻辑。你必须查看is_shutdown()以检查程序是否应该退出(例如有Ctrl+C或其他)。在本例中,代码逻辑即对public .publish(hello_str)的调用,它将一个字符串发布到chatter话题。循环的部分还调用了rate.sleep(),它在循环中可以用刚刚好的睡眠时间维持期望的速率。
你可能也见过rospy.sleep(),它和time.sleep()类似,不同的是前者还能用于模拟时间(参见Clock)。
此循环还调用了rospy.loginfo(str),它有3个任务:打印消息到屏幕上;把消息写入节点的日志文件中;写入rosout。rosout是一个方便的调试工具:您可以使用rqt_console来拉取消息,而不必在控制台窗口找你节点的输出。
std_msgs.msg.String是一个非常简单的消息类型,那更复杂的类型怎么发布呢?一般的经验法则是构造函数参数的顺序与.msg文件中的顺序相同。也可以不传入任何参数,直接初始化字段,例如:
msg = String()
msg.data = str
或者可以只初始化某些字段,并将其余字段保留为默认值:
String(data=str)
你可能会想知道最后一点:
17 try:
18 talker()
19 except rospy.ROSInterruptException:
20 pass
除了标准的Python __main__检查,它还会捕获一个rospy.ROSInterruptException异常,当按下Ctrl+C或节点因其他原因关闭时,这一异常就会被rospy.sleep()和rospy.Rate.sleep()抛出。引发此异常的原因是你不会意外地在sleep()之后继续执行代码。
现在我们需要编写一个节点来接收消息。
编写订阅者节点
代码
下载示例脚本listener.py放到scripts目录中并给执行权限:
$ roscd beginner_tutorials/scripts/
$ wget https://raw.github.com/ros/ros_tutorials/noetic-devel/rospy_tutorials/001_talker_listener/listener.py # 若遇到网络问题,请打开上面文件的链接并复制文本内容到listener.py文件中
$ chmod +x listener.py
文件内容类似于:
1 #!/usr/bin/env python
2 import rospy
3 from std_msgs.msg import String
5 def callback(data):
6 rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
8 def listener():
10 # In ROS, nodes are uniquely named. If two nodes with the same
11 # name are launched, the previous one is kicked off. The
12 # anonymous=True flag means that rospy will choose a unique
13 # name for our 'listener' node so that multiple listeners can
14 # run simultaneously.
15 rospy.init_node('listener', anonymous=True)
17 rospy.Subscriber("chatter", String, callback)
19 # spin() simply keeps python from exiting until this node is stopped
20 rospy.spin()
22 if __name__ == '__main__':
23 listener()
然后,编辑你CMakeLists.txt中的catkin_install_python()调用,如下所示:
catkin_install_python(PROGRAMS scripts/talker.py scripts/listener.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
解释
listener.py的代码类似于talker.py,只不过我们为订阅消息引入了一种新的基于回调的机制。
15 rospy.init_node('listener', anonymous=True)
17 rospy.Subscriber("chatter", String, callback)
19 # spin() simply keeps python from exiting until this node is stopped
20 rospy.spin()
这声明你的节点订阅了chatter话题,类型是std_msgs.msgs.String。当接收到新消息时,callback函数被调用,消息作为第一个参数。
我们还稍微更改了对rospy.init_node()的调用。我们添加了anonymous=True关键字参数。ROS要求每个节点都有一个唯一的名称,如果出现具有相同名称的节点,则会与前一个节点发生冲突,这样一来,出现故障的节点很容易地被踢出网络。anonymous=True标志会告诉rospy为节点生成唯一的名称,这样就很容易可以有多个listener.py一起运行。
最后再补充一下,rospy.spin()只是不让你的节点退出,直到节点被明确关闭。与roscpp不同,rospy.spin()不影响订阅者回调函数,因为它们有自己的线程。
构建节点
我们使用CMake作为构建系统。是的,即使是Python节点也必须使用它。这是为了确保能为创建的消息和服务自动生成Python代码。
回到catkin工作空间,然后运行catkin_make:
$ cd ~/catkin_ws
$ catkin_make
现在你已经编写了一个简单的发布者和订阅者,让我们来测试发布者和订阅者。
检验简单的发布者和订阅者
运行发布者
确保roscore已经开启:
$ roscore
catkin specific 如果使用catkin,在运行你的程序前,请确保你在调用catkin_make后已经source过工作空间的setup.*sh文件:
# 在catkin工作空间中
$ cd ~/catkin_ws
$ source ./devel/setup.bash
上一教程中,我们制作了一个叫做talker的发布者,让我们运行它:
$ rosrun beginner_tutorials talker # (C++)
$ rosrun beginner_tutorials talker.py # (Python)
你会看到:
- [INFO] [WallTime: 1314931831.774057] hello world 1314931831.77
- [INFO] [WallTime: 1314931832.775497] hello world 1314931832.77
- [INFO] [WallTime: 1314931833.778937] hello world 1314931833.78
- [INFO] [WallTime: 1314931834.782059] hello world 1314931834.78
- [INFO] [WallTime: 1314931835.784853] hello world 1314931835.78
- [INFO] [WallTime: 1314931836.788106] hello world 1314931836.79
发布者节点已启动并运行。现在我们需要一个订阅者以接收来自发布者的消息。
运行订阅者
上一教程中,我们也制作了一个叫做listener的订阅者,让我们运行它:
$ rosrun beginner_tutorials listener # (C++)
$ rosrun beginner_tutorials listener.py # (Python)
你会看到:
- [INFO] [WallTime: 1314931969.258941] /listener_17657_1314931968795I heard hello world 1314931969.26
- [INFO] [WallTime: 1314931970.262246] /listener_17657_1314931968795I heard hello world 1314931970.26
- [INFO] [WallTime: 1314931971.266348] /listener_17657_1314931968795I heard hello world 1314931971.26
- [INFO] [WallTime: 1314931972.270429] /listener_17657_1314931968795I heard hello world 1314931972.27
- [INFO] [WallTime: 1314931973.274382] /listener_17657_1314931968795I heard hello world 1314931973.27
- [INFO] [WallTime: 1314931974.277694] /listener_17657_1314931968795I heard hello world 1314931974.28
- [INFO] [WallTime: 1314931975.283708] /listener_17657_1314931968795I heard hello world 1314931975.28
完成后,按Ctrl+C停止listener和talker。
现在已经研究了简单的发布者和订阅者,让我们再编写简单的服务和客户端
编写简单的服务和客户端(Python)
编写服务节点
这里,我们将创建简单的服务(Service)节点add_two_ints_server,该节点将接收两个整数,并返回它们的和。
将当前目录切换到之前的教程中创建的beginner_tutorials包中:
$ roscd beginner_tutorials
请确保你已经按照之前教程中的指示创建了本教程中需要的服务AddTwoInts.srv。(确保在页面顶部选对了所使用的构建工具)
代码
在beginner_tutorials包中创建scripts/add_two_ints_server.py文件并粘贴以下内容进去:
1 #!/usr/bin/env python
2
3 from __future__ import print_function
4
5 from beginner_tutorials.srv import AddTwoInts,AddTwoIntsResponse
6 import rospy
7
8 def handle_add_two_ints(req):
9 print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b)))
10 return AddTwoIntsResponse(req.a + req.b)
11
12 def add_two_ints_server():
13 rospy.init_node('add_two_ints_server')
14 s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
15 print("Ready to add two ints.")
16 rospy.spin()
17
18 if __name__ == "__main__":
19 add_two_ints_server()
别忘了给节点执行权限:
- chmod +x scripts/add_two_ints_server.py
然后将以下内容添加到CMakeLists.txt文件。这样可以确保正确安装Python脚本,并使用合适的Python解释器。
catkin_install_python(PROGRAMS scripts/add_two_ints_server.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
解释
现在,让我们把代码分解。
使用rospy编写服务的难度非常小。我们使用init_node()声明我们的节点,然后再声明我们的服务:
12 s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
这声明了一个名为add_two_ints的新服务,其服务类型为AddTwoInts。所有的请求(request)都传递给了handle_add_two_ints函数。handle_add_two_ints被AddTwoIntsRequest的实例调用,返回AddTwoIntsResponse实例。
就像订阅者中的例子一样,rospy.spin()可以防止代码在服务关闭之前退出。
编写客户端节点
代码
在beginner_tutorials包中创建scripts/add_two_ints_client.py文件并粘贴以下内容进去:
1 #!/usr/bin/env python
2
3 from __future__ import print_function
4
5 import sys
6 import rospy
7 from beginner_tutorials.srv import *
8
9 def add_two_ints_client(x, y):
10 rospy.wait_for_service('add_two_ints')
11 try:
12 add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
13 resp1 = add_two_ints(x, y)
14 return resp1.sum
15 except rospy.ServiceException as e:
16 print("Service call failed: %s"%e)
17
18 def usage():
19 return "%s [x y]"%sys.argv[0]
20
21 if __name__ == "__main__":
22 if len(sys.argv) == 3:
23 x = int(sys.argv[1])
24 y = int(sys.argv[2])
25 else:
26 print(usage())
27 sys.exit(1)
28 print("Requesting %s+%s"%(x, y))
29 print("%s + %s = %s"%(x, y, add_two_ints_client(x, y)))
别忘了给节点执行权限:
$ chmod +x scripts/add_two_ints_client.py
然后,在你的CMakeLists.txt中编辑catkin_install_python()调用,就像这样:
catkin_install_python(PROGRAMS scripts/add_two_ints_server.py scripts/add_two_ints_client.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
解释
现在,让我们把代码分解。
客户端(用来调用服务)的代码也很简单。对于客户端来说不需要调用init_node()。我们首先调用:
10 rospy.wait_for_service('add_two_ints')
这是一种很方便的方法,可以让在add_two_ints服务可用之前一直阻塞。
12 add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
这里我们为服务的调用创建了一个句柄(handle)。
13 resp1 = add_two_ints(x, y)
14 return resp1.sum
然后我们可以使用这个句柄,就像普通的函数一样调用它。
因为我们已经将服务的类型声明为AddTwoInts,它会为你生成AddTwoIntsRequest对象 (you're free to pass in your own instead)。如果调用失败,rospy.ServiceException将会抛出,所以你应该弄一个合适的try/except部分。
构建节点
我们使用CMake作为构建系统。是的,即使是Python节点也必须使用它。这是为了确保能为创建的消息和服务自动生成Python代码。
切换当前目录到你的catkin工作空间,然后运行catkin_make:
# 在你的catkin工作空间中
$ cd ~/catkin_ws
$ catkin_make
现在你已经编写了一个简单的服务和客户端。
检验简单的服务和客户端
运行服务
让我们先开始运行服务:
$ rosrun beginner_tutorials add_two_ints_server # (C++)
$ rosrun beginner_tutorials add_two_ints_server.py # (Python)
你会看到:
Ready to add two ints.
运行客户端
现在,运行客户端并附带必要的参数:
$ rosrun beginner_tutorials add_two_ints_client 1 3 # (C++)
$ rosrun beginner_tutorials add_two_ints_client.py 1 3 # (Python)
你会看到:
Requesting 1+3
1 + 3 = 4
现在,你已经成功地运行了你的第一个服务和客户端。
。