ROS2中python引用自定义py文件(自己写的.py文件)

写在前面:

最近在用ROS2做机器人项目,在单独写好了两个python文件并测试完之后,我需要将python的包放到ROS2中并用ROS2运行
但是在运行的过程中出现了没有办法找到自己写的文件包的错误,具体的错误描述见后
运行环境:
ubuntu 22.04
ROS2 humble


问题描述

在把我的代码放入到ROS2环境下之后,我的工作区目录如下

src/
├── package.xml
├── setup.cfg
├── setup.py
├── swrob_can
│   ├── canbus.py
│   ├── CAN_Recv.py
│   ├── CAN_Send.py
│   ├── __init__.py
│   ├── ...
...

我需要做的是在canbus.py中创建节点,并在其中调用我自己写的CAN _Recv.pyCAN_Send.py中的函数
但是在使用ros2 run canbus,也就是在运行canbus.py中的节点的时候,出现了以下报错

ModuleNotFoundError: No module named 'CAN_Recv'

出现问题的代码其实就是这一句

import CAN_Recv

就是一个简单的在python同路径下引用同路径下的另一个包。而直接用python跑这个程序的是,是完全没有问题的,但是一旦改用ros2 run canbus跑节点的时候,他就找不到这个包。


原因分析:

最后从下面这个链接地址解决了
Including a Python module in a ROS2 package

我自己的理解是如果是自己python直接运行这个代码文件的时候,python可以直接在同路径下直接去找那个函数,但是一旦是使用ROS2 run的时候,其实它是使用的它自己的单独的运行逻辑,我看博客里面看到评论区外国老哥写的点评挺有道理的

Well, I think ROS 2 is still a bit quirky/clumsy in this regard. It was designed to be used in the “ROS” way: you have to build the workspace first, then you can run your program with the ros2 run command. As far as I know, it is not really compatible with “just running files”. The build system is not allowing it to see the submodules in the usual way. I agree this is a disadvantage as it slows down development and makes things more complicated, but for now, this is the cost of the necessary build tool due to platform independentness. To correct this issue, either colcon should be changed, or ROS 2 should use a different build tool or build method.

因此解决问题的关键就是找到在ROS2下应该是一个什么样的路径,或者是怎么调用同路径下的其他文件


解决方案:

在我们需要的节点中稍微改一下代码即可,将import package改为from .package_name import*(引用所有包的所有函数和属性)或者是from .package_name import The_function(引用某个函数)
需要注意的是这里的.就是代表你的节点所在的文件目录
注意改用之后,需要将原python文件下的所有package.function前的pacakge.给删除掉
可以参考一下这个网址
[python]有关Python的import…和from…import…的区别

进一步分析:
其实最重要的地方就是需要去setup.py找我们的包的路径。在setup.py里面有这么一句

package_name = 'mypackage'

setup(
    name=package_name,
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    ...

在前面说的外国老哥的解答方法里面他说,ROS2会将包编译放到workspace/install/lib/python3.8/site-packages/<package_name>中,因此如果里面有,可以直接使用.packagename引用。

注意:如果你引用的自定义包里面还引用了另一个自定义包,则自定义包中的引用也需要改成前面的提示。

大家可以去看一下前面的那个链接网址里面写的方法看一下具体解决方法,他其实提到的是将你自己自定义的包放在另一个路径下,而不是同路径。我这里把原回答贴的内容引用下来

引用网址:https://answers.ros.org/question/367793/including-a-python-module-in-a-ros2-package/
回答人:nagda9
时间:2021年7月21日

原文内容如下:

When ROS2 builds the src files with colcon, it puts the python files into workspace/install/lib/python3.8/site-packages/<package_name>. This folder is considered as the root of python packages in the given ROS 2 package.

If you can find the python files there, then you can use the following import statement: import .<file_name>. Note the . at the start of the import. You don’t have to edit nothing else.

If you want to put the imported files into submodules, then you have to achieve that they show up in the workspace/install/lib/python3.8/site-packages/<package_name>/<submodule_name> folder. This can be done by replacing the packages argument in the setup.py file to the following: packages=["<package_name>", "<packages_name>/<submodule_name>"]. This way the import statement is import .<submodule_name>.<file_name>.

Example file structure to import with submodule:

workspace
|-> ...
|-> src
      |-> mypackage
             |-> mypackage
                    |-> submodules
                           |->__init__.py
                           |-> imported.py
                    |-> __init__.py
                    |-> main.py
             |-> resource
                    |-> ...
             |-> test
                    |-> ...
             |-> package.xml
             |-> setup.cfg
             |-> setup.py

setup.py

from setuptools import setup

package_name = 'mypackage'
submodules = "mypackage/submodules"

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name, submodules],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='TODO',
    maintainer_email='[email protected]',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
    
    
        'console_scripts': [
            'main = mypackage.main:main',
        ],
    },
)

main.py:

from .submodules.imported import function

def main():
    function()
if __name__ == '__main__':
    main()

imported.py:

def function():
    print("hello world")

猜你喜欢

转载自blog.csdn.net/scarecrow_sun/article/details/127589380
今日推荐