能够调用包中写的python文件
mkdir -p learn_ros_ws/src
cd learn_ros_ws/src/
catkin_init_workspace
cd ..
catkin_make
然后我们在命令行中输入
tree -L 1
查看文件夹中的一级目录结构
下面我们将会选用vscode作为集成开发环境,继续创建ros包。
使用vscide中的ros插件创建包
code .
如果之前已经给vscode安装了ros插件,它会识别出这是一个ros工程,自动生成.vscode文件夹。如果事先没有安装,则可以安装后重新打开这个工程。文件结构如下:
其中, c_cpp_properties.json文件记录了编程过程中,头文件和python模块的语法搜索路径,关系到变量名是否会有提示。但,跟编译的时候的搜索路径(CMakeLists.txt中规定的文件搜索路径)不是一回事。
接着我们需要创建 tasks.json文件,编辑编译的指令。
选择catkin_make: build
这时会弹出一个自动生成的tasks文件, 把红框的部分改为Release
这时,我们只需要使用快捷键ctrl+shift+B就能够编译ros工程了,其中args 可以添加更多指令, 达到在命令行中敲指令编译一样的效果。
在src文件夹下右键,选择Create Catkin Package,
依次输入新建包的名字,依赖的包的名字。如名字设为foo_package_1, ros依赖包输入为roscpp rospy std_msgs sensor_msgs geometry_msgs, 这样就建好一个ros包了。结果如图所示:
这里有一点可以稍微留意的是,每一个ros package里面会一个src文件和src外面有一个CMakeLists.txt文件和package.xml文件。这两个文件是需要根据需求改动的。而工作空间learn_ros_ws文件夹src下的CMakeLists.txt让他做个安静的美男子就好了,不需要做任何改动。对于devel和build文件是catkin_make huild的时候自动生成的,如果想重新编译工程,可以直接把这两个文件都删掉再重新编译。值得注意的是,在执行ros空间中的可执行文件前需要在终端source一下devel文件夹下的setup.bash文件,如:
source devel/setup.bash
下面我们按照同样的流程,创建一个名为python_recall_test的包。然后ctrl+shift+B编译一下。最终我们整个ros工程的结构如下。
好,现在万事俱备,下一节我们将会介绍怎么配置建好的ros包,将其封装为一个modules供ros工程里的其他包的python脚本调用。
新建一个scripts/python_recall_test文件夹,然后在其下面新建一个带有utils_foo.py文件的utils文件夹,以及一个foo.py文件。utils_foo.py文件
#! /usr/bin/env python
class WhoAreYou(object):
def __init__(self) -> None:
print('I am python recall test script in utils folder!')
而foo.py文件则写为:
#! /usr/bin/env python
class Foo(object):
def __init__(self) -> None:
print('I am foo in script folder!')
if __name__ == '__main__':
hello = Foo()
只需要解注释 catkin_python_setup() 这个命令即可,可以ctrl+F进行搜索。注意这里改写的ros包里面CMakeLists.txt
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
################################################
可以是空文件,也可以是一个全局定义的函数。这里我们将它放在scripts文件夹中。就我个人习惯而言,我会喜欢把cpp相关的文件放在include和src文件夹中,而python文件则统统扔到scripts文件夹里面。为了示意,在__init__.py中也写了一点东西。
_init_.py 的出现(只看python脚本的名字)告诉了setup.py 文件,同一目录下的所有python文件的模块都可以被外部调用。
最后,CMakeLists.txt所指向的且在ros包中不可或缺的文件setup.py。在这个文件中规定了packages的类型,实际上也是对应我们生成的modules的名字,和调用方式,它规定了在package_dir下的python文件所在路径(此处是scripts文件夹下)。注意看下图中对应的变量名的位置, python_recall_test 和 python_recall_test.utils 为 _init_.py 所在的文件目录,这个文件夹下面的所有文件都可以被当成python模块调用。
# ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD!
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup
# Fetch values from package.xml.
setup_args = generate_distutils_setup(
packages=["python_recall_test", "python_recall_test.utils",], package_dir={"": "scripts"},
)
setup(**setup_args)
最后我们按下ctrl+shift+B 对整个工程进行编译,这样相关的python模块就会在工程根目录的build和devel文件夹下生成某种涉及我知识盲区的链接文件。
最后就只差调用我们写好的python_recall_test 包了。同样的我们在foo_package_1中创建一个scripts文件夹,然后再在scripts文件夹下创建一个main.py脚本,脚本内容如下:
#! /usr/bin/env python
import rospy
from python_recall_test.foo import Foo
from python_recall_test.utils.utils_foo import WhoAreYou
if __name__ == '__main__':
rospy.init_node('test_node')
hi = Foo()
hello = WhoAreYou()
roscore
cd learn_ros_ws/
source devel/setup.bash
rosrun foo_package_1 main.py
程序正常执行,在同一个工程目录下,A包中python模块可以被B包中的python脚本调用的问题,解决!
我们再看一下vscode中的截图情况,会发现竟然没有导入路径找不到时出现的波浪号。
这是因为我们在settings.json里面设置了python的外部搜索路径,你看这个路径的写法跟setup.py文件中的package_dir是不是有点熟悉的味道。当然,关于文件索引的问题,c++的头文件路径也可以在c_cpp_properties.json 文件中定义。
以上就是,如何实现ros包中自定义的python模块被其他包调用的方法总结,需要注意的是,调用前需要source一下工程目录下devel文件夹内的setup.bash文件。
早睡早起精神好!
2022年8月29日凌晨
Dianye Huang