4

我为 ROS2 创建了一个包,并添加了一个我下载的 Python 存储库。我遇到的问题是,在原始存储库中,直接导入了来自自己存储库的模块,而在我的存储库中,我必须导入它们,在模块之前添加 ROS2 包名称,即使我从同一个存储库导入模块,例如:

import planner_pkg.SimpleOneTrailerSystem as SimpleOneTrailerSystem

虽然我想:

import SimpleOneTrailerSystem

我的 ROS2 项目结构如下:

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

包.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>

设置.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',
        ],
    },
)

4

1 回答 1

8

首先,根据Module Search Path文档,当您这样做时,Python在以下位置import something查找:something

  • 从内置模块
  • sys.path,这是一个list包含:
    • 输入脚本的目录
    • PYTHONPATH,这是一个包含目录列表的环境变量
    • 安装相关的默认值

其次,当您构建 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
...

现在,当你这样做时import SimpleOneTrailerSystem,Python 将首先从内置模块中搜索它,它肯定不会在那里找到。名单上的下一个来自sys.path. 您可以在planner_node.pyprint(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...
]

首先sys.path是输入脚本的bin文件夹。那里只有可执行文件,没有SimpleOneTrailerSystem.py文件/模块,因此导入将失败。

列表中的下一个是planner_pkg/lib/pythonX.X/site-packages,从上面的树结构中可以看到,有一个SimpleOneTrailerSystem.py模块,但它位于planner_pkg文件夹下。所以像这样的直接导入

import SimpleOneTrailerSystem

不管用。您需要使用包文件夹对其进行限定,如下所示:

import planner_pkg.SimpleOneTrailerSystem

有两种方法可以解决这个问题。

  1. 修改sys.pathimport_SimpleOneTrailerSystem

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

    此方法将planner_pkg 安装目录的路径添加到sys.path列表中,以便您无需在后续导入中指定它。

  2. PYTHONPATH在运行 ROS2 节点之前进行修改

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

    这种方法与第一种方法几乎相同,但不涉及代码更改(也不涉及重建),因为您只需要修改PYTHONPATH环境变量。

于 2019-10-22T13:04:29.457 回答