【ROS实战】解决Python版本冲突问题并揭秘ROS基本开发流程
前言
初学ROS,开始使用后遇到了两个问题:1. ros.init_node()陷入死循环;2. rosrun [pkg] [filename.py]时陷入死循环。网上针对这两个问题的解答较少,且目前没有找到很好的解答,特此记录解决方式。本文记录的问题和解答包括:
- ROS运行过程中找不到系统中的或是虚拟环境中的python
- 指定anaconda虚拟环境运行ROS
- 配置conda环境时安装相应的包依赖
- ROS工作目录构建和基本开发流程
本文环境配置:Ubuntu 20.04,ros版本为noetic,anaconda虚拟环境中python版本3.8.20,系统自带python版本为3.8.12,路径/usr/bin/python3
文章目录
问题分析与解决
rosrun或是ros.init_node()死循环
首先给出出现问题的原因:运行当前功能包中的代码使用的python版本错误。本文出现这个问题的原因,是编译和运行默认用了anaconda中的base环境(python版本3.12,或者是系统中的python2),即使控制台中已经切换到了一个python3.8的虚拟环境,以及文件开头书写#!/usr/bin/env python3。锁定问题原因,主要是通过切换不同的虚拟环境来看报错的情况,根据切换环境后的一些表现,推断出ROS编译和运行使用的python可能与终端的显示有所不同。例如用python3.8的虚拟环境测试时,如果直接cd到scripts文件夹下利用python filename.py运行文件,运行成功,但是如果rosrun [pkg] [filename.py]则会在ros.init_node()陷入死循环。
catkin_make的编译过程中可以帮助我们锁定当前系统找到的python,例如下图:
这可能也是rosrun等命令运行时调用的python路径,所以思考怎么让catkin_make这一步找到正确的python路径。
在vscode下可以较为方便的指定编译时使用的python路径,具体步骤如下:
- 新建的ROS工程目录下使用快捷键
Ctrl+shift+b(具体的命令是Task build,如果要找自己对应的快捷键,可以进入到"键盘快捷方式"中,搜索"build",如下图)。
图:检查系统快捷键
- 之后选择
catkin_make: build选项后的设置按钮,在初次编译前,在.vscode文件夹下生成tasks.json文件。
图:配置catkin_make: build命令
- 在
tasks.json中,我们指定编译使用的python版本。编译时catkin_make可能只是检测(而不是真的使用)这个python,但是实际测试表明这样的修改使得rosrun等命令也找到了正确版本的python。我们在taks.json中添加一行-DPYTHON_EXECUTABLE=...,其中...就是我们希望使用的python的绝对路径。本文的书写如下(略去一些系统自动生成的内容):
{
"version": "2.0.0",
"tasks": [
{
"type": "catkin_make",
"args": [
"--directory",
"/home/mr-wonderfool/...",
"-DCMAKE_BUILD_TYPE=RelWithDebInfo",
"-DPYTHON_EXECUTABLE=/home/mr-wonderfool/anaconda3/envs/ROS/bin/python"
],
"problemMatcher": [
"$catkin-gcc"
],
"group": "build",
"label": "catkin_make: build"
}
]
}
其中python绝对路径的获取,可以在控制台中激活希望使用的虚拟环境,然后which python得到路径。
4. 至此,在vscode中Ctrl+Shift+b编译时,将使用我们指定的python。同时rosrun等命令也是同步找到了这个python,再使用rosrun不会陷入死循环。
配置运行ROS的anaconda虚拟环境
安装ros-noetic时,系统安装了相应的包依赖,存在/usr/local/lib/python3/dist-packages中,但是我们虚拟环境里面并没有这些包,需要相应安装,步骤如下:
- 对于大部分包,根据运行文件的报错直接
pip install ...即可(例如empy) - 本文在试验时,遇到不好处理的包是
PyKDL,是tf2_ros导入时的依赖,无法直接通过pip安装,需要自己编译之后获取PyKDL.so,具体方法可以参考这篇文章,亲测有效。 - 利用虚拟环境运行时,系统有时会报
import: command not found这样的错误,这是由于系统不知道这个文件需要用python进行编译,所以需要在文件开始处注明#!/usr/bin/env python3。注意这句话主要为了提示系统该文件是python文件,具体env找到的python,仍是我们刚才指明的python。
ROS工作目录构建和基本开发流程
本节总结ROS构建项目和书写文件的基本流程,将上述的两个部分也包括在其中,我们工作区的名称是example_ws,一个功能包的名称是test_pkg:
- 创建文件夹
example_ws,其中创建src,然后catkin_make,命令如下:
mkdir example_ws
cd example_ws && mkdir src && cd ..
catkin_make
通过code .打开example_ws,利用前文所述方式添加tasks.json文件。
cd src/后创建功能包:
cd src
catkin_create_pkg test_pkg [depend1] [depend2] [...]
具体工作目录的样式这里不再赘述,需要注意的是,创建新功能包后,每次新开终端,都要source devel/setup.bash。如果会在这个工作区长时间开发,可以将其写到~/.bashrc中,通过:
echo "source [absolute path]/devel/setup.bash" >> ~/.bashrc
也可以书写一个脚本文件,配合roslaunch等命令一起使用,先source devel/setup.bash再利用roslaunch,这里不展开论述。
- 进入功能包中,创建
scripts文件夹存放所有的python文件。功能包创建伊始会生成src/文件夹,不要在其中书写python文件。开发过程中,在工作区example_ws/和代码文件目录scripts/下分别开一个控制台。 - 在
scripts文件夹下创建.py文件时,尽量不要通过vscode,因为不会自动给文件可执行权限,又会导致rosrun报错,这里推荐命令行的方式(利用开在scripts/下的终端):
cd scripts/
touch test.py
chmod +x test.py
对于新建立的文件,第一行固定写上#!/usr/bin/env python3。
- 重点:每次在
scripts下添加新文件,都要修改src/中的CMakeLists.txt,在其中catkin_install_python添加scripts/[new file].py:
catkin_install_python(PROGRAMS
scripts/test.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
这个主要用于rosrun时补充文件的绝对路径。
进一步,每次修改CMakeLists.txt,都要在工作区目录下(利用开在example_ws下的控制台)重新执行catkin_make
- 补充:
CMakeLists.txt中几个部分的先后顺序:
find_package()
catkin_package()
include_directories()
catkin_install_python()
- 利用
rosrun或者roslaunch运行功能包下的文件即可。
作者:Mr.Wonderfool