简体   繁体   English

在ROS2中导入package中的模块

[英]Import modules in package in ROS2

I have created a package for ROS2 and I have added a Python repository I downloaded.我为 ROS2 创建了一个 package 并添加了一个我下载的 Python 存储库。 The problem I am having is that in the original repository the modules from the own repo were imported directly while in mine I have to import them adding the ROS2 package name before the module, even though I am importing a module from the same repo, like:我遇到的问题是,在原始存储库中,自己的存储库中的模块是直接导入的,而在我的存储库中,我必须导入它们,在模块前添加 ROS2 package 名称,即使我从同一个存储库导入模块,如:

import planner_pkg.SimpleOneTrailerSystem as SimpleOneTrailerSystem

while I would like:而我想:

import SimpleOneTrailerSystem

My ROS2 project structure is like:我的 ROS2 项目结构如下:

ros2_ws
  src
    planner
      planner_pkg
        __init__.py
        SimpleOneTrailerSystem.py
        planner_node.py
        ...
      package.xml
      setup.py

package.xml package.xml

<?xml version="1.0"?>
<package format="2">
  <name>planner_pkg</name>
  <version>0.0.1</version>
  <description>This package contains algorithm for park planner</description>

  <maintainer email=""></maintainer>
  <license>Apache License 2.0</license>

  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <!-- These test dependencies are optional
  Their purpose is to make sure that the code passes the linters -->
  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

setup.py:安装程序.py:

from setuptools import setup

package_name = 'planner_pkg'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    author='',
    author_email='',
    maintainer='',
    maintainer_email='',
    keywords=['ROS'],
    classifiers=[
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Programming Language :: Python',
        'Topic :: Software Development',
    ],
    description='Package containing examples of how to use the rclpy API.',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'planner_node = planner_pkg.planner_node:main',
        ],
    },
)

First, according to the Module Search Path docs, when you do import something , Python looks for that something in the following places:首先,根据Module Search Path文档,当您import something ,Python something在以下位置查找该内容:

  • From the built-in modules从内置模块
  • sys.path , which is a list containing: sys.path ,这是一个包含以下内容的list
    • The directory of the input script输入脚本的目录
    • PYTHONPATH , which is an environment variable containing a list of directories PYTHONPATH ,这是一个包含目录列表的环境变量
    • The installation-dependent default依赖于安装的默认值

Second, when you build your ROS2 Python package (by calling colcon build invoking the ament_python build type), your Python codes will be copied over to an install folder with a tree structure like this:其次,当您构建 ROS2 Python 包时(通过调用colcon build调用ament_python构建类型),您的 Python 代码将被复制到具有如下树结构的安装文件夹:

install
...
├── planner_pkg
│   ├── bin
│   │   └── planner_node
│   ├── lib
│   │   └── python3.6
│   │       └── site-packages
│   │           ├── planner_pkg
│   │           │   ├── __init__.py
│   │           │   ├── planner_node.py
│   │           │   └── SimpleOneTrailerSystem.py
...

Now, when you do import SimpleOneTrailerSystem , Python will first search for it from the built-in modules, which for sure it won't find there.现在,当您import SimpleOneTrailerSystem ,Python 将首先从内置模块中搜索它,它肯定不会在那里找到。 Next on the list is from sys.path .列表中的下一个来自sys.path You can add a print(sys.path) at the top of planner_node.py to see something like this list:您可以在planner_node.py的顶部添加一个print(sys.path)以查看类似以下列表的内容:

['/path/to/install/planner_pkg/bin', 
 '/path/to/install/planner_pkg/lib/python3.6/site-packages', 
 '/opt/ros/eloquent/lib/python3.6/site-packages', 
 '/usr/lib/python36.zip', 
 '/usr/lib/python3.6', 
 ...other Python3.6 installation-dependent dirs...
]

First on the sys.path list is the bin folder of the input script. sys.path列表中的第一个是输入脚本的bin文件夹。 There are only executables there, no SimpleOneTrailerSystem.py file/module, so that import will fail.那里只有可执行文件,没有SimpleOneTrailerSystem.py文件/模块,因此导入将失败。

The next on the list would be the planner_pkg/lib/pythonX.X/site-packages , and as you can see from the tree structure above, there is a SimpleOneTrailerSystem.py module BUT it is under a planner_pkg folder .列表中的下一个是planner_pkg/lib/pythonX.X/site-packages ,从上面的树结构中可以看出,有一个SimpleOneTrailerSystem.py模块,但它位于planner_pkg文件夹下 So a direct import like this所以像这样直接导入

import SimpleOneTrailerSystem

will not work.不管用。 You need to qualify it with the package folder like this:您需要使用包文件夹来限定它,如下所示:

import planner_pkg.SimpleOneTrailerSystem

There are 2 ways to get around this.有两种方法可以解决这个问题。

  1. Modify sys.path before import -ing SimpleOneTrailerSystem import前修改sys.path -ing SimpleOneTrailerSystem

     import sys sys.path.append("/path/to/install/planner_pkg/lib/python3.6/site-packages/planner_pkg") import SimpleOneTrailerSystem

    This approach adds the path to the planner_pkg install directory to the sys.path list so that you don't need to specify it in subsequent imports.此方法将planner_pkg安装目录的路径添加到sys.path列表中,以便您无需在后续导入中指定它。

  2. Modify PYTHONPATH before running your ROS2 node在运行 ROS2 节点之前修改PYTHONPATH

     $ colcon build $ source install/setup.bash $ export PYTHONPATH=$PYTHONPATH:/path/to/install/planner_pkg/lib/python3.6/site-packages/planner_pkg $ planner_node

    This approach is almost the same as the first one, but there is no code change involved (and no rebuilding involved), as you only need to modify the PYTHONPATH environment variable.这种方法与第一种方法几乎相同,但不涉及代码更改(也不涉及重建),因为您只需要修改PYTHONPATH环境变量。

I had the same problem and fixed it by modifying setup.py.我有同样的问题并通过修改 setup.py 修复它。

Add:添加:

('lib/' + package_name, [package_name+'/SimpleOneTrailerSystem.py']), ('lib/' + package_name, [package_name+'/SimpleOneTrailerSystem.py']),

to "data_files" list.到“data_files”列表。

setup.py:安装程序.py:

from setuptools import setup

package_name = 'planner_pkg'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        ('lib/' + package_name, [package_name+'/SimpleOneTrailerSystem.py']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    author='',
    author_email='',
    maintainer='',
    maintainer_email='',
    keywords=['ROS'],
    classifiers=[
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Programming Language :: Python',
        'Topic :: Software Development',
    ],
    description='Package containing examples of how to use the rclpy API.',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'planner_node = planner_pkg.planner_node:main',
        ],
    },
)

For CMAKE packages with cpp and python code you can add the following lines to your CMakeLists.txt.对于带有 cpp 的 CMAKE 包和 python 代码,您可以将以下行添加到您的 CMakeLists.txt。 This will copy your python_pkg folder into your install environment to "lib/python{version}/site-packages" which is per default included in your python path.这会将您的 python_pkg 文件夹复制到安装环境中的“lib/python{version}/site-packages”,默认包含在您的 python 路径中。

# for python code
find_package(ament_cmake_python REQUIRED)
find_package(rclpy REQUIRED)

install(DIRECTORY
    ../path_to_python_pkg
    DESTINATION lib/python3.8/site-packages
)

install(PROGRAMS
    ${PROJECT_NAME}/python_node.py
    DESTINATION lib/${PROJECT_NAME}
)

ament_python_install_package(${PROJECT_NAME})

If you are using eg Dashing or Eloquent it is "python3.6", for Foxy or newer it is "python3.8"如果您使用的是 Dashing 或 Eloquent,则它是“python3.6”,对于 Foxy 或更新版本,它是“python3.8”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM