客户端库(Client Libarary)不仅仅指的是C++、Python语言的接口,其实是各种语言的接口统称。roscpp是最常用的接口,但是c++开发周期相对较长。本文我们来学习ROS的另一个接口rospy,也即是Python语言的接口。
1. rospy vs roscpp
rospy是Python版本的ROS客户端库,提供了Python编程需要的接口,你可以认为rospy就是一个Python的模块(Module)。这个模块位于/opt/ros/kineetic/lib/python2.7/dist-packages/rospy
之中。
rospy包含的功能与roscpp相似,都有关于node、topic、service、param、time相关的操作。但同时rospy和roscpp也有一些区别:
- rospy没有一个NodeHandle,像创建publisher、subscriber等操作都被直接封装成了rospy中的函数或类,调用起来简单直观。
- rospy一些接口的命名和roscpp不一致,有些地方需要开发者注意,避免调用错误。
相比于C++的开发,用Python来写ROS程序开发效率大大提高,诸如显示、类型转换等细节不再需要我们注意,节省时间。但Python的执行效率较低,同样一个功能用Python运行的耗时会高于C++。因此我们开发SLAM、路径规划、机器视觉等方面的算法时,往往优先选择C++。但ROS中绝大多数基本指令,例如rostopic
,roslaunch
都是用python开发的,简单轻巧。
2. 代码组织形式
对于一些小体量的ROS程序,一般就是一个Python文件,放在script/路径下,非常简单。
1 | pkg_name |
当程序的功能比较复杂,放在一个脚本里搞不定时,就需要把一些功能放到Python Module里,以便其他的脚本来调用。ROS建议我们按照以下规范来建立一个Python的模块:
1 | pkg_name |
在src下建立一个与你的package同名的路径,其中存放_init_.py
以及你的模块文件。这样就建立好了ROS规范的Python模块,你可以在你的脚本中调用。
3. Topic通信的实现
3.1 创建功能包
1 | catkin_create_pkg topic_demo rospy std_msgs |
3.2 定义.msg文件
在topic_demo/msg文件夹下创建一个自定义的gps类型的消息,一个节点发布模拟的gps信息,另一个接收和计算距离原点的距离。
gps.msg
定义如下:
1 | string state #工作状态 |
我们需要修改CMakeLists.txt
文件:
1 | find_package(catkin REQUIRED COMPONENTS |
package.xml
中需要的改动:
1 | <depend>message_generation</depend> |
完成了以上所有工作,就可以回到工作空间,然后catkin_make
了。
这里需要强调一点的就是,对创建的msg进行catkin_make
会在~/catkin_ws/devel/lib/python2.7/dist-packages/topic_demo
下生成msg模块(module)。 有了这个模块,我们就可以在python程序中from topic_demo.msg import gps
,从而进行gps类型消息的读写。
3.3 话题发布节点
topic_demo/scripts/pytalker.py:
1 | #!/usr/bin/env python |
以上代码与C++的区别体现在这几个方面:
- rospy创建和初始化一个node,不再需要用NodeHandle。rospy中没有设计NodeHandle这个句柄,我们创建topic、service等等操作都直接用rospy里对应的方法就行。
- rospy中节点的初始化并一定得放在程序的开头,在Publisher建立后再初始化也没问题。
- 消息的创建更加简单,比如gps类型的消息可以直接用类似于构造函数的方式
gps(state,x,y)
来创建。 - 日志的输出方式不同,C++中是
ROS_INFO()
,而Python中是rospy.loginfo()
- 判断节点是否关闭的函数不同,C++用的是
ros::ok()
而Python中的接口是rospy.is_shutdown()
通过以上的区别可以看出,roscpp和rospy的接口并不一致,在名称上要尽量避免混用。在实现原理上,两套客户端库也有各自的实现,并没有基于一个统一的核心库来开发。这也是ROS在设计上不足的地方。
3.4 话题订阅节点
topic_demo/scripts/pylistener.py:
1 | #!/usr/bin/env python |
在订阅节点的代码里,rospy与roscpp有一个不同的地方:rospy里没有spinOnce()
,只有spin()
。
建立完talker和listener之后,经过catkin_make
,就完成了python版的topic通信模型。
4. Service通信的实现
4.1 创建功能包
1 | catkin_create_pkg service_demo rospy std_msgs |
4.2 定义.srv文件
在service_demo/srv目录下一个名为Greeting.srv
的服务文件,内容如下:
1 | string name |
然后修改CMakeLists.txt
文件。ROS的catkin编译系统会将你自定义的msg、srv(甚至还有action)文件自动编译构建,生成对应的Python语言下可用的库或模块。许多初学者错误地以为,只要建立了一个.msg或.srv文件,就可以直接在程序中使用,这是不对的,必须在CMakeLists.txt
中添加关于消息创建、指定消息/服务文件那几个宏命令并完成编译才能生成可用的消息或服务内容。
事实上,对于服务,会生成三个类:Greeting, GreetingRequese以及GreetingResponse。
4.3 服务提供节点
service_demo/scripts/server_demo.py:
1 | #!/usr/bin/env python |
handle_function()传入的只有request,返回值是response,即:
1 | def handle_function(req): |
4.4 服务请求节点
service_demo/scripts/client_demo.py:
1 | #!/usr/bin/env python |
以上代码中greetings_client.call("HAN",20)
等同于greetings_client("HAN",20)
。
5. 参数服务器
rospy关于参数服务器的API包括了增删查改等用法: rospy.get_param()
,rospy.set_param()
,rospy.has_param()
,rospy.delete_param()
,rospy.search_param()
,rospy.get_param_names()
。
1 | #!/usr/bin/env python |