🤖 roboto_origin_03 Wiki
首页 / 电机子模块 / CAN总线接口配置

在调用 MotorDriver::create_motor() 创建电机实例之前,必须确保 Linux 系统的 CAN 总线接口已经正确初始化并处于 UP 状态。本页面向初学者讲解如何在 Ubuntu/Debian 系统中使用 ip 命令激活 SocketCAN 接口,涵盖标准 CAN 2.0 与 CAN-FD 两种模式,并说明接口名称(如 can0)在 SDK 内部是如何被使用的。完成本节配置后,方可继续编译 SDK 或运行示例程序。

Sources: README_CN.md

前置条件

开始配置前,请确认硬件与内核环境满足以下要求。若缺失对应硬件或内核模块,后续所有 ip 命令都会报错 No such device

Sources: socket_can.cpp

检查项 期望结果 自检命令
CAN 适配器已连接 USB-CAN 分析仪或板载 CAN 控制器已接入系统 lsusblspci 能看到设备
CAN 内核模块已加载 cancan_rawvcan(可选)等模块已加载 `lsmod
存在 CAN 网络接口 系统已生成 can0can1 等网络设备 ip link show type can

若使用虚拟 CAN(vcan)进行本地测试,可额外加载 vcan 模块并创建虚拟接口,但真实电机控制必须使用物理 CAN 适配器。

Sources: socket_can.cpp

配置流程概览

下面的流程图展示了从硬件连接到代码运行的完整准备路径。建议按照编号顺序执行。

flowchart TD
    A[连接CAN适配器到PC] --> B{确认接口名称}
    B -->|can0 / can1| C[选择通信模式]
    C -->|DM EVO LRO| D[标准CAN 2.0]
    C -->|Xynova| E[CAN-FD]
    D --> F[执行ip link set up]
    E --> G[执行ip link set up fd on]
    F --> H[验证接口状态]
    G --> H
    H --> I[运行SDK或示例程序]

Sources: motor_driver.hpp

标准 CAN 2.0 配置(DM / EVO / LeadRobot)

大多数电机驱动器使用标准 CAN 2.0 协议,数据段长度固定为 8 字节,波特率通常设置为 1 Mbps。假设系统识别的接口名为 can0,在终端执行以下命令:

sudo ip link set can0 down
sudo ip link set can0 up type can bitrate 1000000

命令拆解如下:down 先关闭接口以确保状态重置;up 激活接口;type can 指定为经典 CAN;bitrate 1000000 将仲裁段与数据段均设为 1 Mbps。若系统存在多条 CAN 总线,请将 can0 替换为实际接口名(如 can1)。

Sources: socket_can.cpp

接口名称与 SDK 的关联

在创建电机对象时,第三个参数 interface 必须与上述 ip link 命令中的接口名保持一致。如下表所示,字符串 "can0" 会原样传入 MotorsSocketCAN,随后通过 ioctl(SIOCGIFINDEX) 绑定到内核的对应网络设备。

Sources: dm_motor_driver.cpp

位置 代码/命令示例 说明
系统配置 sudo ip link set can0 up ... 接口名 can0
C++ 创建电机 MotorDriver::create_motor(0x01, "can", "can0", "DM", 0) 第三个参数为 "can0"
Python 创建电机 MotorDriver.create_motor(..., interface="can0", ...) interface 参数为 "can0"
驱动内部绑定 MotorsCAN::get("can0") 单例管理,同一名称共享同一 socket

若接口名拼写错误(例如写成 can0 但系统实际为 can1),MotorsSocketCAN::open() 会在 ioctl 阶段抛出异常并提示 Unable to detect CAN interface

Sources: socket_can.cpp

CAN-FD 配置(Xynova)

CAN-FD 在经典 CAN 基础上扩展了数据段长度(最高 64 字节)与数据段波特率。若使用支持 CAN-FD 的电机,需要在激活接口时显式开启 FD 模式并设置数据段速率。以 can0 为例:

sudo ip link set can0 down
sudo ip link set can0 up type can bitrate 1000000 dbitrate 5000000 fd on

其中 bitrate 1000000 为仲裁段速率,dbitrate 5000000 为数据段速率,fd on 启用 CAN-FD 支持。具体波特率应以电机厂商手册为准。

Sources: socket_canfd.cpp

在 SDK 层面,CAN-FD 与标准 CAN 的接口命名规则完全相同,仍通过 interface="can0" 指定。区别在于 DmMotorDriver(或其他驱动)内部会根据 interface_type=="canfd" 调用 MotorsCANFD::get(),后者在创建 socket 时会额外执行 setsockopt(sockfd_, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, ...) 以启用 FD 帧解析。

Sources: socket_canfd.cpp

配置持久化(重启后保持生效)

上述 ip 命令在系统重启后会失效。若希望接口开机自动激活,推荐使用 systemd-networkd。创建配置文件 /etc/systemd/network/80-can.network

[Match]
Name=can*

[CAN]
BitRate=1000000

对于 CAN-FD,则需额外指定数据段速率,部分发行版需借助自定义 udev 规则或 @after 脚本。由于不同 Linux 发行版的网络管理工具差异较大,本页仅提供最常见方案,具体持久化方法请参考对应系统文档。

验证与排错

配置完成后,使用以下命令检查接口状态:

ip -details link show can0

期望输出应包含 <UP, RUNNING, NOARP> 状态字样,且 qlen 不为 0。

Sources: socket_can.cpp

常见问题速查表

现象 根因 解决方法
No such device 接口名错误或未识别到硬件 执行 ip link show type can 确认真实接口名
Device or resource busy 接口已被其他程序占用 sudo ip link set can0 down 再重新 up
Operation not permitted 权限不足 使用 sudo 执行,或将用户加入 netdev
SDK 日志提示 Unable to detect CAN interface create_motor() 中的接口名与系统不一致 核对 ip link 输出与代码中的 interface 参数
能发送但收不到数据 波特率不匹配或终端电阻缺失 确认电机与适配器波特率一致,检查总线终端电阻
CAN-FD 帧发送失败 未启用 fd on 或适配器不支持 FD 确认 ip link 命令包含 fd on,并核实硬件规格

Sources: socket_can.cpp, socket_canfd.cpp

SDK 内部是如何绑定接口的

对于希望理解底层机制的读者,下图展示了从操作系统网络接口到电机驱动实例的映射关系。MotorsSocketCAN 采用单例模式管理每个接口名称:同一进程内,所有使用 "can0" 的电机共享同一个 socket 文件描述符,从而避免重复创建内核对象;不同接口(如 "can0""can1")则各自拥有独立实例。

graph LR
    subgraph 操作系统层
        A[can0<br/>ip link set up]
        B[can1<br/>ip link set up]
    end
    subgraph SDK协议层
        C[MotorsSocketCAN<br/>单例: "can0"]
        D[MotorsSocketCAN<br/>单例: "can1"]
    end
    subgraph 驱动层
        E[DM电机 #1<br/>can_=MotorsCAN::get("can0")]
        F[EVO电机 #2<br/>can_=MotorsCAN::get("can0")]
        G[LRO电机 #3<br/>can_=MotorsCAN::get("can1")]
    end
    A -->|socket+ioctl+bind| C
    B -->|socket+ioctl+bind| D
    C -->|共享| E
    C -->|共享| F
    D -->|独享| G

当电机驱动被销毁时,它会调用 remove_can_callback() 注销自身的接收回调,但不会关闭 socket;直到所有引用该接口的驱动实例均释放后,MotorsSocketCAN 析构函数才会关闭底层 socket 并恢复线程资源。

Sources: can_iso.hpp, socket_can.hpp, motor_driver.hpp

下一步

完成 CAN 接口配置后,请继续阅读: