1. 所用系统为ubuntu18.04 ros版本为melodic。
  2. 正常ros melodic不支持python3, 只支持python2。所以需要新建一个工作空间在工作空间下创建虚拟环境。
  3. ubunut20.04可以安装ros noetic版本。

一、创建工作空间及虚拟环境

使用Python3和Python2.7的混合环境
原理:使用virtualenv创建一个Python3的环境。然后在这个环境中编译安装自己需要的软件包。在引用软件包的时候,如果没有对应的Python3的软件包,会自动的去Python2.7的环境里面找。这样很多软件包都是可以通用的。当然对于没有做好Python3支持的软件包也是没法用的。

mkdir catkin_ws # 创建工作空间
cd catkin_ws
mkdir src
cd src 
# 下载geometry和geometry2的源代码
git clone https://github.com/ros/geometry
git clone https://github.com/ros/geometry2
cd ..
# 创建虚拟环境
virtualenv -p /usr/bin/python3 venv        #这一步伐是创建虚拟环境。
source venv/bin/activate                              #这一步是激活虚拟环境。
pip install catkin_pkg pyyaml empy rospkg numpy          #安装python3虚拟环境下所需的编译依赖之类的。
catkin_make
source devel/setup.bash

二、创建功能包,编写发布者py文件,为其添加执行权限,修改cmakelists.txt进行编译。

正常创建功能包即可,无需激活虚拟环境,注意:一般ros的功能包中cpp文件都是放在src目录下的。而.py文件则需在和src同级目录下创建一个scripts文件夹,在里面编写.py文件。
发布者.py代码:

#!/usr/bin/env python3    
#-*-coding:utf-8-*-

import rospy
from std_msgs.msg import String
def talker():
     pub = rospy.Publisher('chatter', String, queue_size=10)
     rospy.init_node('talker', anonymous=True)
     rate = rospy.Rate(10) # 10hz
     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

注意:py文件第一行必须加上 #!/usr/bin/env python3 否则无法运行代码。相当于解释器。
为test_pub.py添加执行权限:

chmod +x test_pub.py

然后修改cmakelists.txt进行编译。其实python是不需要修改cmakelists.txt进行编译的,因为python本身为脚本文件,无需编译,只需添加权限就能运行。下面在cmakelists.txt中加入这条是为了用launch启动这个文件时能够找到它,如果是用rosrun运行,不加也是可以的。
cmakelist.txt中加入:

catkin_install_python(PROGRAMS
  scripts/test_pub.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

然后回到编译目标下进行编译。
编译时注意:如果代码中需要用python3的一些库,如numpy1.19.5,pytorch1.7d等。就需要进行激活虚拟环境进行编译,否则会提示找不到包或者模块。
注意:在ros中编译python文件不会像cpp文件一样生成可执行文件。运行时还是:rosun 功能包名字 test_pub.py。

三、编写订阅者cpp

和正常ros编写cpp一样。
test1.cpp:

//本例子为实现了ros的c++与python通信,而且这个python是python3的版本。


#include "ros/ros.h"
#include "std_msgs/String.h"
 
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
	ROS_INFO("I lol heard: [%s]", msg->data.c_str());
}
 
int main(int argc, char *argv[])
{

	ros::init(argc, argv, "listener");
	ros::NodeHandle n;
	ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
	ros::spin();
 
	return 0;
}

四、运行代码。

运行代码和ros操作步骤一样,同样如果需要虚拟环境,激活即可,否则不需要。

注意

在ros节点中用python3相关函数写内容时,比如要读取一个视频并将其一帧一帧转化成ros消息发布出去,此时就需要用到cv_bridge。然而如果直接import cv_bridge,它导入的依然是python2.7中的cv_bridge包。为此我们需要和将python3和ros连接起来的cv_bridge包。 说明:建立ros与python3通信使用的cv_bridge过程其实就是新建一个ros工作空间,然后在github上下载相应的包。然后编译过后会在计算机相应文件夹下生成dist-packages,然后在编写节点时,在导入cv_bridge之前,先用sys.path.remove()移除python2.7对应的dist-packages的路径,用sys.path.append()加入你生成的dist-packages的路径即可。 此外针对ros的python,没有rospy.spinonce()这个函数,因此订阅到图像后无法直接将图像的信息通过全局变量传到主函数中进行检测跟踪等处理。因此可采用多线程的方法进行。即多开一个线程,使其专门跑rospy.spin()进行回调函数的订阅。然后在我们的主线程中,什么时候需要检测跟踪了获取一下变量即可。

五、参考连接

Python为ROS编写一个简单的发布者和订阅者