- 上一讲的内容是关于ROS和C++编程的,这一讲我们来聊聊ROS和Python编程。同样,关于工作空间、功能包、CMakeList.txt、package.xml等内容我就不再阐述,这一讲的内容主要在于ROS和Python的接口,以及ROS开发的一个“通性”。
创建功能包learning_python
cd catkin_ws/src
catkin_create_pkg learning_python rospy roscpp std_msgs
- 这次的功能包名称叫做learning_python,意在学习ROS下Python开发。我们这次需要在工作空间下创建scripts文件夹,意为“脚本”。这里我们再重复以下,ROS功能包下的src放的是源码,include是引用文件,scritps是脚本文件,这也算是默认的潜规则,我们进入learning_python路径下,建立scripts文件夹。
mkdir scripts
修改CMakeList.txt和package.xml
- 我们需要对这两个文件进行一些小小的改动,对比C++的ROS开发,Python的ROS开发简单和方便的无数倍。下面是我修改后的package.xml。
<?xml version="1.0"?>
<package format="2">
<name>learning_python</name>
<version>0.0.0</version>
<description>这是学习ROS Python编程的功能包</description>
<maintainer email="1692697820@qq.com">waveshare</maintainer>
<license>TODO</license>
<author email="1692697820@qq.com">waveshare</author>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>message_generation</build_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
<export>
</export>
</package>
cmake_minimum_required(VERSION 3.0.2)
project(learning_python)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES learning_python
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
- 这些内容和上一节的很相似,唯一不同的就是没有了编译依赖项等待一大堆链接,这就是Python简洁性的体现。
使用Python实现ROS编程
- 我们这一章实现的功能和上一章相同,可以让大家对比一下C++实现和Python实现的 异同所在。
- 首先写一个发布节点,我们需要在scritps文件夹下,创建publisher.py,并赋予该文件可执行权限。Python很特别的,它的程序即是源码文件,也是执行文件。如果我们没有给可执行权限的话,1那么我们的rosrun会一直找不到节点(可执行文件)。
roscd learning_python
cd scripts
touch publisher.py
sudo chmod +777 publisher.py
#!/usr/bin/env python #指定Python运行,即Python2
#coding:utf‐8 #设置编码格式为utf‐8
import rospy #导入rospy功能包
from std_msgs.msg import String #导入std_msgs/String消息功能包
#定义talker函数
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10)
#定义发布的主题名称chatter,消息类型String,实质是std_msgs.msg.String
#设置队列条目个数为10
rospy.init_node('talker', anonymous=True)
#初始化节点,节点名称为talker,
#anonymous=True,要求每个节点都有唯一的名称,避免冲突
rate = rospy.Rate(10)
#设置发布的频率,单位是每秒次数,这是每秒10次的频率发布主题
#用于检测程序是否退出,是否按Ctrl‐C 或其他
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str) #在屏幕输出日志信息
pub.publish(hello_str) #发布信息到主题
rate.sleep() #睡眠一定持续时间
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
然后进行编译。
- 我们之前在C++下面写有订阅节点,可以来验证一下这个Python发布节点是否正确。我们依次启动ROS Master节点管理器、learning_python下的publisher.py发布节点脚本、learning_cplus下的listener订阅节点。
- 启动ROS Master节点管理器。
roscore
- 启动learning_python下的publisher.py发布节点脚本。
rosrun learning_python publisher.py
- 启动learning_cplus下的listener订阅节点。
rosrun learning_cplus listener
- 我们来启动一个rqt_graph节点关系图来查看一下节点关系。
rqt_graph
- 其中的的talker就是我们的Python发布节点,listener就是我们的C++订阅节点。接下来开始写订阅节点,老规矩,进入scripts文件夹,创建listener.py订阅节点文件, 然后赋予可执行权限。
roscd learning_python
cd scripts
touch listener.py
sudo chmod +777 listener.py
#!/usr/bin/env python #指定Python运行,即Python2
#coding:utf‐8 #设置编码格式为utf‐8
import rospy #导入rospy功能包
from std_msgs.msg import String #导入std_msgs/String消息功能包
#定义回调函数
def callback(data):
rospy.loginfo(rospy.get_caller_id() + 'I heard %s', data.data)
def listener():
rospy.init_node('listener', anonymous=True)
#初始化节点,节点名称为talker
#anonymous=True,要求每个节点都有唯一的名称,避免冲突
rospy.Subscriber('chatter', String, callback)
#订阅函数,订阅chatter主题,内容类型是std_msgs.msgs.String。
#当有新内容,调用callback函数处理。接受到的主题内容作为参数传递给callback.
rospy.spin()
#保持节点运行,直到节点关闭。
#不像roscpp,rospy.spin不影响订阅的回调函数,因为回调函数有自己的线程。
if __name__ == '__main__':
listener()
- 然后来验证一下订阅节点的一个功能。
- 启动ROS Master节点管理器。
roscore
- 启动learning_python下的publisher.py发布节点脚本。
rosrun learning_python publisher.py
- 启动learning_cplus下的listener订阅节点。
rosrun learning_python listener.py
可以看到,这是相当成功的。
- 我们可以对比一下C++的实现和Python的实现,可以看到原理和过程是一模一样的, 只是在关键字和语法方面有所不同。 初始化节点,发布消息声明,然后发布,延时;再或者就是定义回调函数,监听,延 时。当中的核心重点是在于发布的一个数据的格式。 假如说我现在想做一个惯导IMU,可是你不懂四元数(咳咳,这个不是重点)计算,但 是再这个时候你却发现,ROS有对惯导模块的功能包(比如imu_tools功能包),那么你需 要做的就是搞清楚这个功能包之间关系,看陀螺仪所获得数据是如何达到,又达到了哪个位 置。这就是ROS! 同样,大家也可以试一下发布一个cmd_vel老控制小海龟的运动!
|