1.问题
ros2 python编写程序, 有多个python文件
- 如何打包多个python文件?
- 解决import错误问题
- 如何打包 有python目录结构的工程
1.ros2 多个python文件示例
代码目录结构, gitee 在线代码
tree 7_multi_file_setup/
7_multi_file_setup/
├── file1.py
├── main_node.py
file1.py
file1_config={"lili":123, "makr": 222}
main_node.py
导入file1.py 的 file1_config文件
# 导入本地模块
from file1 import *
def main():
print("file1_config:", file1_config)
if __name__ == "__main__":
main()
setup.py
from setuptools import find_packages, setup
package_name = '7_multi_file_setup'
setup(
name=package_name,
version='0.0.0',
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='liuj',
maintainer_email='lj1637664504@outlook.com',
description='TODO: Package description',
license='TODO: License declaration',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'main_node = 7_multi_file_setup.main_node:main',
],
},
)
2.运行错误: import error "No module named ‘file1’ "
编译: colcon build --packages-select 7_multi_file_setup
运行:
source install/setup.bash
ros2 run 7_multi_file_setup main_node
Traceback (most recent call last):
File "/home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/7_multi_file_setup/main_node", line 33, in <module>
sys.exit(load_entry_point('7-multi-file-setup==0.0.0', 'console_scripts', 'main_node')())
File "/home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/7_multi_file_setup/main_node", line 25, in importlib_load_entry_point
return next(matches).load()
File "/usr/lib/python3.10/importlib/metadata/__init__.py", line 171, in load
module = import_module(match.group('module'))
File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/python3.10/site-packages/7_multi_file_setup/main_node.py", line 2, in <module>
from file1 import *
ModuleNotFoundError: No module named 'file1'
[ros2run]: Process exited with failure 1
3.问题原因: ros2 run的import 路径, 与 ros2 python 打包安装路径不一致
main_node.py 打印 import sys.path导入模块路径
import sys
def show_ros_module_import_path():
# 获取当前脚本所在的目录
print("ros2 import module path:")
for path in sys.path:
print(path)
show_ros_module_import_path()
# 导入本地模块
from file1 import *
def main():
print("file1_config:", file1_config)
if __name__ == "__main__":
main()
3.1 ros2 run 打印 import module 导入模块路径结果
ros2 run 7_multi_file_setup main_node
ros2 import module path:
/home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/7_multi_file_setup
/home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/python3.10/site-packages
/opt/ros/humble/lib/python3.10/site-packages
/opt/ros/humble/local/lib/python3.10/dist-packages
/usr/lib/python310.zip
/usr/lib/python3.10
/usr/lib/python3.10/lib-dynload
/home/liuj/.local/lib/python3.10/site-packages
/usr/local/lib/python3.10/dist-packages
/usr/lib/python3/dist-packages
3.2 实际的文件路径
tree install/7_multi_file_setup/
install/7_multi_file_setup/
├── lib
│ ├── 7_multi_file_setup
│ │ └── main_node
│ └── python3.10
│ └── site-packages
│ ├── 7_multi_file_setup
│ │ ├── file1.py
│ │ ├── main_node.py
4.问题小结
- ros2 run 程序 import 导入模块路径: /home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/python3.10/site-packages
- 实际文件路径: /home/liuj/3_work/7_ros-robot-example/ros2/install/7_multi_file_setup/lib/python3.10/site-packages/7_multi_file_setup/file1.py
- ros2 run 运行时sys.path import路径, 与 实际 ros2/install/package 打包安装代码路径不一致
2.解决方法
解决方案1: 拷贝 python 代码到 import 路径
ros2 install安装路径: ros2/install/package/lib/package
示例安装路径: ros2/install/7_multi_file_setup/lib/7_multi_file_setup
修改setup.py, 拷贝python代码到 import路径
setup.py
++ import os
from glob import glob
from setuptools import find_packages, setup
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
++ (os.path.join('lib', package_name), glob('7_multi_file_setup/*.py')),
],
install_requires=['setuptools'],
zip_safe=True,
验证测试
编译: colcon build --packages-select 7_multi_file_setup
打包路径:
ls install/7_multi_file_setup/lib/7_multi_file_setup/
2_添加模块路径_append_module_dir.py file1.py main_node main_node.py
运行结果: ros2 run 7_multi_file_setup main_node
file1_config: {‘lili’: 123, ‘makr’: 222}
解决方案2: sys.path 添加 install/package/lib/sitepackage代码路径
在ros2 python代码, 添加本地模块之前, 加入下面的函数
import os
import sys
def ros_append_module_dir():
# 获取当前脚本的绝对路径
script_path = os.path.abspath(__file__)
# 获取当前脚本所在的目录
script_dir = os.path.dirname(script_path)
sys.path.append(script_dir)
ros_append_module_dir()
# 重要
# 重要
# 重要
# 导入本地模块之前
重要:
- ros_append_module_dir() 添加到本地模块之前
- ros_append_module_dir() 添加到本地模块之前
ros_append_module_dir() 添加到本地模块之前
- ros_append_module_dir() insert before import local_module
原理解析:
本质是将 ros2 run package main_node --> main_node.py 文件路径添加到 sys.path中
3.python代码目录拷贝
如下, 代码目录中有 protobuf/ 目录, 如何拷贝目录
tree -L 7_multi_file_setup/
7_multi_file_setup/
├── main_node.py
├── protobuf
│ ├── websocket.py
│ └── websocket.proto
解决方法
setup.py
data_files=[
('share/ament_index/resource_index/packages',['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name), glob('launch/*_launch.py')),
++ (os.path.join('lib', package_name,'protobuf'), glob('network_proxy/protobuf/*.py')),
],
打包安装目录:
install/7_multi_file_setup/lib/7_multi_file_setup/protobuf/websocket.py
4.推荐方案 与 总结
1.推荐方案
个人推荐使用 解决方案1: 拷贝代码到import路径
理由:
- 无需修改源代码
- 解决 带 ros2 python 多个子目录结构时, site-packages 不打包子目录的问题
缺点:
4. install 目录代码多拷贝一份, 安装包文件体积变大
疑问:
是否有其它更优解决方法?
- 不修改源码, 只修改配置项
2.总结
- 要熟悉python import 与 sys.path 之间的关系
- 要熟悉setup.py 如何打包
个人签名
一个linux-网络-系统-固件-内核驱动-嵌入式-机器人开发工程师
个人微信