roboto_imu 的 Python SDK 基于 pybind11 将 C++ 核心驱动封装为原生扩展模块 imu_py,使 Python 开发者无需编写 C++ 代码即可实时读取超核电子(HiPNUC)系列 IMU 的传感器数据。本页面向初次接触的初学者,聚焦 Python 模块的编译安装、导入配置、基础 API 调用与常见错误排查,假设你已具备 Python 基础语法知识。更底层的编译依赖与系统配置请参考前文 环境依赖与安装。
Sources: src/pybind_module.cpp
环境准备
在构建 Python 模块之前,请确认系统已安装 python3-dev 与 pybind11-dev(或 ROS 2 环境下的 pybind11_vendor)。CMake 通过 find_package(Python3 COMPONENTS Interpreter Development REQUIRED) 与 find_package(pybind11 REQUIRED) 自动探测 Python 解释器与头文件路径,若探测失败,编译将中止并提示缺失依赖。本项目要求 Python 版本不低于 3.8,且编译与运行需使用同一解释器,否则可能出现符号未定义错误。
Sources: CMakeLists.txt, package.xml
编译与安装
Python 模块并非独立构建,而是随 C++ 静态库一同编译。在 ROS 2 工作空间内执行 colcon build --packages-select roboto_imu 后,imu_py*.so 会被放置在 install/roboto_imu/lib/python3.x/site-packages/ 目录下;若采用纯 CMake 构建,则默认安装到系统前缀(如 /usr/local/lib/python3.x/site-packages/);若使用 build_deb.sh 打包部署,安装前缀固定为 /opt/roboparty。无论哪种方式,构建完成后都建议通过 find 命令定位 .so 文件,以确认 Python 模块确实已生成。
Sources: CMakeLists.txt, build_deb.sh
配置 Python 模块路径
由于安装路径并非系统默认的 dist-packages,初学者最常遇到的错误是 ModuleNotFoundError: No module named 'imu_py'。最直接的做法是将模块所在目录加入 PYTHONPATH,例如在 bash 中执行 export PYTHONPATH=/opt/roboparty/lib/python3.10/site-packages:$PYTHONPATH(请根据实际 Python 小版本号替换 3.10)。更持久的方案是在系统 site-packages 或虚拟环境的 site-packages 中创建一个 .pth 文件,如 echo "/opt/roboparty/lib/python3.10/site-packages" | sudo tee /usr/lib/python3/dist-packages/roboto-imu.pth,这样每次启动 Python 时解释器都会自动扫描该路径。完成配置后,运行 python3 -c "from imu_py import IMUDriver; print('OK')" 验证导入是否成功。
Sources: CMakeLists.txt
Python SDK 架构一览
为了帮助你理解 Python 脚本与底层硬件之间的调用关系,下图展示了 Python SDK 的分层架构。你的 Python 代码通过 import imu_py 加载由 pybind11 生成的共享对象,该对象内部持有 std::shared_ptr<IMUDriver> 并转发所有方法调用到 C++ 抽象基类,再由具体驱动完成 CAN 帧或串口字节流的收发。
graph TD
A[Python 脚本] -->|import imu_py| B[pybind11 绑定层<br/>imu_py.so]
B -->|调用 C++ API| C[IMUDriver 抽象基类]
C --> D[HipnucIMUDriver 实现]
D -->|CAN 帧| E[SocketCAN 单例]
D -->|UART 字节流| F[SerialPort]
E --> G[CAN 协议解析]
F --> H[私有协议解码]
Sources: src/pybind_module.cpp
五分钟入门示例
当模块可正常导入后,即可在 Python 中创建 IMU 实例并读取数据。整个流程可分为四个步骤:导入模块、调用工厂方法 create_imu 创建实例、循环读取传感器数据、按需处理或打印结果。下图以流程图形式展现了这一最小闭环,后文将分别给出 CAN 与串口的完整可运行代码。
flowchart LR
A[导入 imu_py] --> B[create_imu 创建实例]
B --> C[get_quat / get_ang_vel<br/>读取数据]
C --> D[业务处理或打印]
Sources: src/pybind_module.cpp, include/imu_driver.hpp
CAN 接口示例
以下示例展示了如何通过 CAN 接口连接 IMU。假设你的设备节点地址为 0x08,且主机 can0 接口已启用并与设备处于相同波特率。create_imu 的 baudrate 参数在 CAN 模式下无实际作用,通常填 0 即可。实例创建后,底层会自动启动实时接收线程,将解析后的传感器数据更新到内部缓冲区,你只需调用对应的 getter 方法即可拿到最新一帧数据。
from imu_py import IMUDriver
import time
imu = IMUDriver.create_imu(
imu_id=0x08,
interface_type="can",
interface="can0",
imu_type="HIPNUC",
baudrate=0
)
while True:
print("Quaternion:", imu.get_quat()) # [w, x, y, z]
print("Angular Velocity:", imu.get_ang_vel()) # [x, y, z] rad/s
print("Linear Accel:", imu.get_lin_acc()) # [x, y, z] m/s²
print("Temperature:", imu.get_temperature()) # °C
time.sleep(0.1)
Sources: README_CN.md, src/pybind_module.cpp
串口接口示例
若使用串口通信,仅需将 interface_type 改为 "serial",interface 改为设备节点路径(如 "/dev/ttyUSB0"),并根据设备实际配置设置 baudrate。常见波特率包括 9600、115200、921600 等。串口模式下底层同样会启动独立的 SCHED_FIFO 实时接收线程,通过 select 阻塞读取并在收到完整数据包后触发解码回调,因此你的 Python 主循环无需关心字节流拼接细节。
from imu_py import IMUDriver
import time
imu = IMUDriver.create_imu(
imu_id=0x01,
interface_type="serial",
interface="/dev/ttyUSB0",
imu_type="HIPNUC",
baudrate=115200
)
while True:
print("Quaternion:", imu.get_quat())
print("Angular Velocity:", imu.get_ang_vel())
print("Linear Accel:", imu.get_lin_acc())
print("Temperature:", imu.get_temperature())
time.sleep(0.1)
Sources: README_CN.md, src/protocol/serial/serial_port.cpp
API 参数与方法速查
为了便于快速查阅,下表汇总了 create_imu 工厂方法的参数定义与实例可调用方法。所有 getter 方法均为线程安全的读操作,可直接在主循环中调用,但返回的是最近一次成功解码的数据快照;若设备尚未上电或通信异常,返回值可能保持初始零值。
create_imu 参数说明
| 参数 | Python 类型 | 必填 | 说明 |
|---|---|---|---|
imu_id |
int |
是 | 设备节点地址,CAN 时用于过滤总线上的目标设备 |
interface_type |
str |
是 | 通信方式,取值为 "can" 或 "serial" |
interface |
str |
是 | CAN 接口名(如 "can0")或串口路径(如 "/dev/ttyUSB0") |
imu_type |
str |
是 | 驱动类型,当前仅支持 "HIPNUC" |
baudrate |
int |
否 | 串口波特率,CAN 场景下可忽略或填 0,默认值为 0 |
实例方法速查
| 方法 | 返回值 | 单位 / 说明 |
|---|---|---|
get_quat() |
list[float] |
四元数 [w, x, y, z],无单位 |
get_ang_vel() |
list[float] |
角速度 [x, y, z],单位 rad/s |
get_lin_acc() |
list[float] |
线加速度 [x, y, z],单位 m/s² |
get_temperature() |
float |
温度,单位 °C |
get_imu_id() |
int |
返回实例化时传入的设备地址 |
Sources: src/pybind_module.cpp, include/imu_driver.hpp
虚拟环境注意事项
许多初学者习惯在虚拟环境(venv)中开发,但需要注意 imu_py 是编译型扩展,其构建过程会绑定到具体的 Python 解释器与头文件版本。如果你使用系统 Python 编译,却在另一个虚拟环境中运行,且该虚拟环境的 Python 小版本号不同(例如系统为 3.10,venv 为 3.11),则会出现 ImportError: undefined symbol 或 libpython 相关错误。建议始终在计划运行扩展的同一个 Python 环境中执行编译,或确保虚拟环境使用与系统一致的解释器。对于 ROS 2 用户,colcon 通常使用系统 Python,source 工作空间的 setup.bash 后即可直接导入。
Sources: CMakeLists.txt
常见问题排查
下表整理了 Python 初学者在首次使用本 SDK 时最可能遇到的五种现象及其根因与修复方法。若按照前文步骤仍无法读取数据,建议先对照此表逐项排查,再深入到硬件接口专题页面定位问题。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
ModuleNotFoundError: No module named 'imu_py' |
模块路径未加入 sys.path |
配置 PYTHONPATH 或 .pth 文件 |
ImportError: undefined symbol: ... |
Python 编译与运行版本不一致 | 在同一 Python 环境下重新编译 |
Permission denied: /dev/ttyUSB0 |
当前用户无串口设备权限 | sudo usermod -aG dialout $USER 后重新登录 |
can0: No such device |
CAN 接口未创建或未启用 | 执行 sudo ip link set can0 up type can bitrate 1000000 |
所有 getter 返回 [0.0, ...] |
设备未响应或 imu_id / 波特率错误 |
检查物理接线、设备地址与波特率配置 |
Sources: README_CN.md, init_imu.sh
下一步阅读
完成本页的快速上手后,你已经能够通过 Python 读取 IMU 的实时姿态与运动数据。接下来建议根据你的硬件接口类型,深入阅读对应的配置指南以掌握排错与调优技巧;若对 Python 绑定背后的 C++ 实现感兴趣,也可翻阅 pybind11 机制专题。推荐的阅读顺序如下:首先根据接口选择 CAN 接口配置指南 或 串口接口配置指南;随后可阅读 传感器数据访问与线程安全 以理解数据在并发场景下的更新语义;最后,若希望为其他型号 IMU 扩展 Python 支持,可研读 pybind11 Python 绑定机制 了解绑定代码的编写规范。