如何使用 ROS 导入自定义 python 模块?

Posted

技术标签:

【中文标题】如何使用 ROS 导入自定义 python 模块?【英文标题】:How to import custom python modules with ROS? 【发布时间】:2021-08-24 16:31:50 【问题描述】:

在模拟器.py 中,我从 Control 导入了 PID.py,根据 PyCharm IDE 是有效的。

程序结构:

src
├── quantum_drone
│   ├── CMakeLists.txt
│   ├── Control
│   │   ├── __init__.py
│   │   ├── Keys.py
│   │   ├── MonotonicTime.py
│   │   └── PID.py
│   ├── package.xml
│   └── scripts
│       ├── __init__.py
│       └── simulator.py

我意识到我的根目录 (quantum_drone) 中没有 setup.py 设置,所以我什么时候设置了它:

#!/usr/bin/env python
# noinspection PyUnresolvedReferences
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup
   
# fetch values from package.xml
setup_args = generate_distutils_setup(
     packages=['quantum_drone'],
     scripts=['Control', 'scripts'],
     package_dir='': 'src',
 )
 
setup(**setup_args)

在我的 CMakeLists.txt 中,我取消了 catkin_python_setup() 的注释,并在 catkin_install_python 中写道:

catkin_install_python(PROGRAMS
   scripts/simulator.py
   Control/PID.py
   DESTINATION $CATKIN_PACKAGE_BIN_DESTINATION
)

最后,我跑了:

catkin_make 
source devel/setup.bash

我尝试运行: rosrun quantum_drone simulator.py

但我不断收到这条消息:

Traceback (most recent call last):
  Traceback (most recent call last):
  File "/home/kannachan/drone/src/quantum_drone/scripts/simulator.py", line 3, in <module>
    from Control import PID
ImportError: No module named Control

我可以发誓我做了我需要做的所有事情,所以我不确定我什么时候出错了,以至于我无法导入我的文件/目录。

PID.py的内容(我可以导入MonotonicTime.py就好了):

#!/usr/bin/env python

from pymavlink import mavutil
from MonotonicTime import monotonic_time
import numpy as np

current_time = monotonic_time


class PID:

    def __init__(self, vehicle, kp=0, ki=0, kd=0, velocity=(0, 0, 0)):
        self.kp = kp  # Constants (kp, ki, kd)
        self.ki = ki
        self.kd = kd
        self.drone = vehicle
        self.p_terms = np.array([0, 0, 0], dtype=float)  # 3-axis
        self.i_terms = np.array([0, 0, 0], dtype=float)
        self.d_terms = np.array([0, 0, 0], dtype=float)
        self.velocity = np.asarray(velocity)  # Desired Velocity
        self.current_velocity = np.array(self.drone.velocity)  # Current Velocity
        self.errors = np.array([0, 0, 0], dtype=float)  # Previous Error
        self.time = current_time()  # Current Time
        self.__max__ = 40  # Max Speed
        self.__min__ = 0  # Min Speed

    def reset(self):
        #  Resetting terms
        self.p_terms = np.array([0, 0, 0], dtype=float)
        self.i_terms = np.array([0, 0, 0], dtype=float)
        self.d_terms = np.array([0, 0, 0], dtype=float)
        self.errors = np.array([0, 0, 0], dtype=float)

    def calculate_change(self):
        now = current_time()
        delta_error = self.velocity - self.current_velocity  # Change in error
        delta_time = now - self.time if now - self.time else 1e-16  # Change in time
        self.time = now
        return delta_error, delta_time

    def pid_calculation(self):
        delta_error, delta_time = self.calculate_change()
        # PID controller formula
        self.p_terms = delta_error * self.kp
        self.i_terms += self.errors * delta_time
        self.d_terms = (delta_error - self.errors) / delta_time
        self.errors = delta_error
        outputs = self.kp * self.p_terms + self.ki * self.i_terms + self.kd * self.d_terms
        outputs = np.where(outputs > self.__max__, self.__max__, outputs)  # Replacing terms too big
        outputs = np.where(outputs < self.__min__, self.__min__, outputs)  # Replacing terms too small
        return outputs

    def send_command(self):
        vx, vy, vz = self.pid_calculation()
        msg = self.drone.message_factory.set_position_target_location_ned_encode(
            0,
            0, 0,
            mavutil.mavlink.MAV_FRAME_BODY_NED,
            0b0000111111000111,
            0, 0, 0,
            vx, vy, vz,
            0, 0
        )
        self.drone.send_mavlink(msg)
        self.drone.flush()

【问题讨论】:

【参考方案1】:

您的导入错误。它应该从 PID 而不是 Control 导入。同样,在 ROS1 中,Python 包不需要 setup.py 文件。

【讨论】:

不确定我是否阅读正确,但我将from Control import PID 更改为from Control.PID import PID。这仍然给了我同样的错误,还是我误解了你的答案? 对不起,如果我不清楚,我的意思是你不应该尝试从 Control 导入,因为当 catkin 安装包时没有控制文件夹。你需要from PID import &lt;classname&gt; 我无法直接从 Control 目录导入 PID,所以我必须将 file:///home/kannachan/drone/src/quantum_drone/Control 添加到路径中。我尝试了from PID import PID 并运行rosrun quantum_drone simulator.py,它给了我一个类似的错误,它找不到模块。 请使用 PID.py 的内容编辑您的帖子。您也不应该将包源添加到您的搜索路径中。 我刚刚用 PID.py 的内容更新了帖子。 PID.py 和 MonotonicTime.py 位于名为 Control 的同一目录中,我可以很好地导入它们。但是,当我尝试从名为 scripts 的目录中导入 PID.py 时,它会出现错误,所以我想知道程序结构是否是这里的问题。只是为了确保,我是否正确地执行了 catkin_install_python?

以上是关于如何使用 ROS 导入自定义 python 模块?的主要内容,如果未能解决你的问题,请参考以下文章

python导入同一目录下的自定义模块,出现ModuleNotFoundError

python如何导入自定义文件和模块全部方法

python如何导入自定义文件和模块

vscode如何配置debug,python正则表达式如何匹配括号,关于python如何导入自定义模块

Python调用自定义模块方法有啥

python导入自带模块和自定义模块