本文从物理目录结构、逻辑分层设计和模块依赖关系三个维度,系统性地介绍 roboto_motors SDK 的整体架构。理解这些顶层设计决策,是后续深入各子系统实现细节、甚至扩展新电机品牌或通信后端的前提。本代码库面向多品牌伺服电机(达妙 DM、EVO、LeadRobot)提供统一的 C++/Python 控制接口,并在通信层抽象了 CAN 2.0、CAN-FD 与 EtherCAT 三种总线形态。
Sources: CMakeLists.txt
逻辑分层架构
SDK 采用经典的分层架构,自上而下可分为语言绑定层、核心抽象层、电机驱动实现层、通信协议层与基础设施层。各层之间通过显式接口契约交互,下层对上层透明,而上层不感知下层具体实现。这种结构使得新增一个电机品牌或更换总线后端时,无需改动上层业务代码。
flowchart TB
subgraph L1["语言绑定层"]
PY["pybind_module.cpp<br/>Python SDK 导出"]
end
subgraph L2["核心抽象层"]
MD["MotorDriver 抽象基类<br/>工厂方法 create_motor()"]
end
subgraph L3["电机驱动实现层"]
DM["DmMotorDriver"]
EVO["EvoMotorDriver"]
LRO["LroMotorDriver"]
end
subgraph L4["通信协议层"]
subgraph CAN["CAN 2.0"]
CAN_ISO["MotorsCAN 接口"]
SOC["MotorsSocketCAN<br/>单例 + 无锁队列"]
end
subgraph CANFD["CAN-FD"]
CANFD_ISO["MotorsCANFD 接口"]
SOCFD["MotorsSocketCANFD<br/>单例 + 无锁队列"]
end
subgraph ECAT["EtherCAT (预留)"]
ECAT_ISO["MotorsEtherCAT 接口"]
end
end
subgraph L5["基础设施层"]
UTIL["utils.hpp<br/>日志 / 限幅 / 计时器"]
end
L1 --> L2
L2 --> DM
L2 --> EVO
L2 --> LRO
DM --> CAN_ISO
DM --> CANFD_ISO
EVO --> CAN_ISO
EVO --> CANFD_ISO
LRO --> CANFD_ISO
CAN_ISO --> SOC
CANFD_ISO --> SOCFD
DM --> UTIL
EVO --> UTIL
LRO --> UTIL
SOC --> UTIL
SOCFD --> UTIL
核心设计意图:MotorDriver 基类定义了所有电机公共行为的契约(初始化、锁止、MIT/位置/速度控制、状态刷新、错误清除等),而通信协议层进一步将帧发送与回调注册抽象为 MotorsCAN / MotorsCANFD / MotorsEtherCAT 三个独立接口。电机驱动实现层位于两者之间,负责将高层控制指令翻译成特定品牌的总线帧格式,并通过协议层接口完成物理收发。这种双层抽象(设备抽象 + 总线抽象)是系统能够横向扩展的根本。
Sources: motor_driver.hpp, can_iso.hpp, canfd_iso.hpp
物理目录与构建单元
代码的物理组织严格映射到逻辑分层。src/ 下的每个一级子目录在 CMake 中对应一个独立静态库,最终由顶层 CMakeLists.txt 汇总链接为 motors 主库,并生成 motors_py Python 扩展模块。
src/
├── motor_driver.cpp # 工厂方法与基类日志初始化
├── pybind_module.cpp # Python 绑定入口
├── utils.hpp # 跨模块工具集
├── CMakeLists.txt # 聚合 drivers / protocol
├── drivers/
│ ├── CMakeLists.txt
│ ├── dm/ # dm_motors 静态库
│ ├── evo/ # evo_motors 静态库
│ └── lro/ # lro_motors 静态库
└── protocol/
├── CMakeLists.txt
├── can/ # motors_can 静态库
├── canfd/ # motors_canfd 静态库
├── can_iso.hpp # CAN 2.0 抽象接口
├── canfd_iso.hpp # CAN-FD 抽象接口
└── ethercat_iso.hpp # EtherCAT 抽象接口 (预留)
顶层构建脚本显式声明了所有子库的最终链接关系:motors 依赖 dm_motors evo_motors lro_motors motors_can motors_canfd。这意味着如果未来加入第四个品牌(如注释中预留的 XYN),只需新增一个静态库并追加到链接列表即可,不会破坏现有模块的编译边界。
Sources: src/CMakeLists.txt, CMakeLists.txt
模块职责对照表
下表按从顶至底的顺序列出各模块的职责边界、关键类/文件以及它们对外提供的核心价值。
| 模块 | 核心文件 | 主要职责 | 对外暴露的关键接口 |
|---|---|---|---|
| Python 绑定 | src/pybind_module.cpp |
通过 pybind11 将 C++ 类和方法导出为 Python 模块 motors_py |
MotorDriver.create_motor(), motor_mit_cmd(), get_motor_pos() 等 |
| 核心抽象 | include/motor_driver.hpp<br>src/motor_driver.cpp |
定义电机统一接口契约与工厂方法;管理跨模块 spdlog 日志器 | MotorDriver 基类、create_motor() 静态工厂 |
| DM 驱动 | src/drivers/dm/dm_motor_driver.hpp/cpp |
达妙 DM 电机协议转换:MIT/位置/速度指令编码、状态解码、寄存器读写 | DmMotorDriver 继承 MotorDriver |
| EVO 驱动 | src/drivers/evo/evo_motor_driver.hpp/cpp |
EVO 电机协议转换:含 Flash 烧录、多反馈类型解析、CAN-FD 扩展帧支持 | EvoMotorDriver 继承 MotorDriver |
| LRO 驱动 | src/drivers/lro/lro_motor_driver.hpp/cpp |
LeadRobot 电机协议转换:配置模式、查询模式、零位设置、错误清除 | LroMotorDriver 继承 MotorDriver |
| CAN 协议 | src/protocol/can_iso.hpp<br>src/protocol/can/socket_can.hpp/cpp |
定义 CAN 2.0 抽象接口;提供基于 Linux SocketCAN 的单例实现,含收发线程与无锁发送队列 | MotorsCAN 接口、MotorsSocketCAN::get() |
| CAN-FD 协议 | src/protocol/canfd_iso.hpp<br>src/protocol/canfd/socket_canfd.hpp/cpp |
定义 CAN-FD 抽象接口;提供 SocketCAN-FD 单例实现,结构与 CAN 模块对称 | MotorsCANFD 接口、MotorsSocketCANFD::get() |
| EtherCAT 协议 | src/protocol/ethercat_iso.hpp |
定义 EtherCAT 抽象接口(帧结构、回调类型),预留 SOEM/IgH 后端接入点 | MotorsEtherCAT 接口 |
| 基础设施 | src/utils.hpp |
提供限幅、数值映射、L1/L2 范数、高精度计时器、日志器初始化等跨模块工具 | limit(), range_map(), Timer, setup_logger() |
各电机驱动模块仅依赖其所需的协议子集:DM 同时支持 CAN 与 CAN-FD,EVO 同样兼容两者,而 LRO 当前仅依赖 CAN-FD(代码中 EtherCAT 部分已被注释预留)。这种按需依赖避免了不必要的编译耦合。
Sources: dm_motor_driver.hpp, evo_motor_driver.hpp, lro_motor_driver.hpp
模块间依赖关系
从链接依赖角度,整个系统呈现为“倒置树”形状:顶层 motors 静态库聚合所有子库,而 Python 扩展 motors_py 唯一依赖 motors。子库之间不存在横向依赖——例如 dm_motors 不引用 evo_motors,它们只共享公共的 motor_driver.hpp 头文件和 utils.hpp 工具集。
flowchart LR
PY["motors_py<br/>(Python扩展)"]
MOT["motors<br/>(主静态库)"]
DM["dm_motors"]
EVO["evo_motors"]
LRO["lro_motors"]
CAN["motors_can"]
CANFD["motors_canfd"]
PY --> MOT
MOT --> DM
MOT --> EVO
MOT --> LRO
MOT --> CAN
MOT --> CANFD
DM --> CAN
DM --> CANFD
EVO --> CAN
EVO --> CANFD
LRO --> CANFD
这种依赖结构带来两个工程优势:一是增量编译友好,修改单个品牌驱动不会触发全量重编译;二是安装接口清晰,motors 库作为唯一对外暴露的 C++ 链接目标,配合 include/motor_driver.hpp 公共头文件,即可满足绝大多数集成场景。
Sources: CMakeLists.txt
横向扩展机制
架构在两个维度上为扩展预留了明确的接入点,这也是理解“模块划分”深层意图的关键。
新增电机品牌:开发者需要创建新的子目录(如 src/drivers/xyn/),继承 MotorDriver 并实现全部纯虚方法,然后在 src/motor_driver.cpp 的工厂方法中追加分支判断。协议层已有的 MotorsCAN / MotorsCANFD 接口可直接复用,无需重写 SocketCAN 逻辑。
新增通信后端:以 CAN-FD 为例,当前仅有 MotorsSocketCANFD 一个实现,但 MotorsCANFD 接口的 get() 工厂方法在设计上已预留 backend 参数(如 "socketcan"、"ethercat"、"shm")。未来若需加入基于共享内存或 EtherCAT 桥接的 CAN-FD 后端,只需新增一个实现类并注册到工厂即可,所有电机驱动代码零改动。
Sources: motor_driver.cpp, canfd_iso.hpp
建议阅读路径
架构总览的意义在于建立全局认知,下一步可根据实际关注点深入特定模块:
- 若关注统一接口设计与工厂实例化,请继续阅读 MotorDriver抽象基类与接口设计 与 工厂模式与多品牌电机实例化。
- 若关注通信层实现细节,请阅读 CAN/CANFD协议抽象接口 与 SocketCAN单例与无锁发送队列。
- 若关注特定品牌电机的协议与控制逻辑,请按需跳转 达妙DM电机驱动详解、EVO电机驱动详解 或 LeadRobot电机驱动详解。
- 若关注构建系统与部署,请阅读 CMake构建系统与依赖管理 与 Debian包构建与发布。