I have created a package for ROS2 and I have added a Python repository I downloaded. 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:
import planner_pkg.SimpleOneTrailerSystem as SimpleOneTrailerSystem
while I would like:
import SimpleOneTrailerSystem
My ROS2 project structure is like:
ros2_ws
src
planner
planner_pkg
__init__.py
SimpleOneTrailerSystem.py
planner_node.py
...
package.xml
setup.py
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:
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:
sys.path
, which is a list
containing:
PYTHONPATH
, which is an environment variable containing a list of directoriesSecond, 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:
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. Next on the list is from sys.path
. You can add a print(sys.path)
at the top of planner_node.py to see something like this list:
['/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. There are only executables there, no SimpleOneTrailerSystem.py file/module, so that import will fail.
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. 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.
Modify sys.path
before import
-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.
Modify PYTHONPATH
before running your ROS2 node
$ 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With