上篇对比了SPI/I2C/UART/CAN四种协议。这篇深入CAN总线——在机器人领域,CAN是电机驱动和多轴协调的事实标准。面试中CAN相关的题目深度往往超出预期,不只是"知道CAN是什么",而是帧格式、错误处理、总线调度这些细节。

CAN帧结构

一个标准CAN数据帧由以下部分组成:

帧起始(SOF,1位)→ 仲裁段(12位:11位ID+RTR)→ 控制段(6位:IDE+RTR+DLC)→ 数据段(0-8字节)→ CRC段(15位CRC+1位分隔符)→ ACK段(2位)→ 帧结束(7位)。

几个关键细节:

  • DLC(Data Length Code)表示数据长度,0-8字节。CAN FD扩展到0-64字节。
  • RTR(Remote Transmission Request)位用于远程帧——请求另一个节点发送数据。远程帧没有数据段。
  • CRC是15位CRC-15,生成多项式为X^15+X^14+X^10+X^8+X^7+X^4+X^3+1。硬件自动计算和校验。
  • ACK槽。发送节点发隐性位(1),接收节点在ACK槽发显性位(0)。如果发送节点检测到隐性位,说明没有节点正确接收,触发错误处理。

CAN的位时序也值得了解。每个CAN位被分为多个时间段:同步段(SS)、传播段(Prop)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2)。采样点的位置(通常在75%-87.5%处)影响通信的稳定性。采样点太靠前容易受干扰,太靠后容错能力差。CiA推荐在75%处,但很多实际系统用87.5%。配置位时序参数(SJW、TSEG1、TSEG2)时,要确保所有节点的采样点位置一致,否则在高负载时会出现错误。

CAN的仲裁机制

CAN的仲裁是其最精妙的设计。多个节点同时发送时:

  1. 所有节点在SOF后开始逐位发送ID
  2. 每个节点在发送隐性位(1)的同时检测总线电平
  3. 如果检测到显性位(0),说明有更高优先级的节点在发送
  4. 该节点退出仲裁,转为接收状态
  5. 等当前帧结束后再尝试发送

仲裁是非破坏性的——胜出节点的帧完整发送,没有任何延迟或数据损坏。ID值越小优先级越高(因为显性位0优先)。

这个机制有一个重要推论:如果你需要保证某个消息的实时性,给它分配一个较小的ID。在机器人中,急停信号、关节位置反馈这些高实时性消息应该用低ID。

错误处理机制

CAN有五种错误类型:

  1. 位错误(Bit Error):发送节点检测到的总线电平与发送的位不一致
  2. 填充错误(Fill Error):连续6个相同极性的位(违反位填充规则)
  3. CRC错误:接收到的CRC与计算值不匹配
  4. 格式错误(Form Error):固定格式字段中出现非法位
  5. ACK错误:ACK槽中没有检测到显性位

每个CAN节点维护两个错误计数器:TEC(发送错误计数器)和REC(接收错误计数器)。根据计数器值,节点处于三种状态:

  • Error Active(TEC<128且REC<128):正常参与通信
  • Error Passive(TEC≥128或REC≥128):可以收发,但发送错误帧时延迟发送
  • Bus Off(TEC≥256):断开总线,不参与任何通信

Bus Off后,节点需要等待128个11位隐性时间(约1.28ms@1Mbps)才能尝试恢复。这个机制保证了故障节点不会持续干扰总线。

错误帧的结构也值得了解。错误帧由错误标志(6个连续相同极性位,违反位填充规则)和错误分隔符(8个隐性位)组成。叠加错误(多个节点同时发错误帧)时,隐性位会被显性位覆盖,形成"叠加原则"——确保所有检测到错误的节点都知道有其他节点也检测到了错误。这种设计让错误处理本身也是非破坏性的。

CAN FD:经典CAN的升级

CAN FD(Flexible Data-rate)解决了经典CAN的两个痛点:数据段最大8字节太小,带宽利用率不够。

CAN FD的改进:

  • 数据段最大64字节(8/12/16/20/24/32/48/64)
  • 仲裁段用标称比特率(比如500kbps),数据段切换到更高比特率(比如2Mbps或5Mbps)
  • 改进的CRC(CRC-17用于≤16字节,CRC-21用于>16字节)
  • 去掉了远程帧(实际项目中几乎不用)

CAN FD与经典CAN在物理层兼容(同样的差分线),但CAN FD控制器可以处理两种帧。混合部署时需要注意:经典CAN节点无法理解CAN FD帧的BRS位,会把它当作错误。解决方案是CAN FD网络中不混入经典CAN节点,或者用网关隔离。

CAN FD的实际部署建议:数据段切换到高速率时,对布线质量要求更高。如果线缆质量不好或者分支太长,高速段可能出现信号完整性问题。经验法则是:仲裁段500kbps、数据段2Mbps是大多数线缆能稳定工作的组合。如果要用5Mbps或8Mbps,需要用专用线缆并严格控制分支长度(每个stub不超过0.3米)。另外,CAN FD的CRC-21比经典CAN的CRC-15更强,错误检测率提高了约100倍——这对安全性要求高的应用(比如协作机器人)很重要。

CAN在机器人中的应用

在机器人中,CAN主要用于电机驱动器的通信。典型的架构:一个主控制器(比如运行ROS2的工控机)通过USB-CAN适配器连接到CAN总线,总线上挂着6-12个电机驱动器。

通信协议通常是主从式:主控制器周期性地发送控制指令(目标位置/速度/力矩),各驱动器回复状态反馈(实际位置/电流/温度)。常见的开源协议有:

  • CANopen:工业标准,基于CAN的应用层协议,定义了对象字典、PDO(过程数据对象)、SDO(服务数据对象)
  • CiA 402:基于CANopen的驱动器配置文件,定义了状态机和控制字

ODrive、Moteus、MIT的mini-cheetah驱动器都使用自定义的CAN协议,但核心思路类似:简洁的命令帧+状态反馈帧,周期1ms。

自定义CAN协议的设计原则:第一,尽量用标准帧(11位ID),不要用扩展帧(29位ID),因为扩展帧的开销更大且很多工具支持不好。第二,数据对齐用整型而不是浮点——CAN总线上没有标准化的浮点编码,把角度乘以1000传整数(毫度精度)比传IEEE754浮点数更可靠。第三,心跳机制是必须的——主控制器周期性发送心跳帧,驱动器超过一定时间没收到就进入安全状态(通常是零力矩模式)。第四,紧急停止用最高优先级ID,确保在任何总线负载下都能及时传达。

面试要点

CAN为什么用差分信号。差分信号抗共模干扰——外部电磁干扰同时耦合到CAN_H和CAN_L上,接收端只检测两者的电压差,共模噪声被抵消。这就是为什么CAN可以在工业环境中稳定工作。

CAN总线的终端电阻。两端各120Ω,并联后60Ω。这是为了匹配双绞线的特性阻抗(约60-120Ω),防止信号在末端反射。如果总线很长或分支很多,可能需要额外的终端电阻。

位填充(bit stuffing)的作用。CAN协议规定连续5个相同极性的位后必须插入一个相反极性的位。这保证了足够的信号跳变密度,让接收端的时钟恢复电路能正确同步。接收端自动去除填充位。

CAN总线的最大负载率。面试中可能问你:1Mbps的CAN总线,理论最大帧率是多少?一个标准数据帧(8字节数据)约111位,加上帧间间隔(3位),每秒最多约1Mbps÷114≈8772帧。实际中总线负载率建议不超过70%——超过后仲裁延迟急剧增加,实时性无法保证。

给你的建议

如果你要深入学习CAN,建议从CANopen开始。CANopen虽然复杂,但它展示了如何在CAN上构建完整的应用层协议——NMT(网络管理)、PDO(实时数据)、SDO(配置参数)、EMCY(紧急报文)。理解了CANopen,再写自定义协议就很简单了。

调试CAN问题需要工具。入门级用USB-CAN适配器(比如CANable,几十美元),配合PCAN-View或BusMaster软件抓包分析。专业级用Vector的CANoe或PCAN,支持总线负载分析、错误帧统计、DBC文件解析。DBC文件是CAN数据库的描述文件,定义了每个ID的含义和信号布局,是多节点协作的基础。

最后一个建议:在写CAN驱动之前,先用现成的工具把协议跑通。用PCAN-View手动发送帧,确认硬件连接和波特率正确,再写代码。很多CAN通信问题其实是硬件层面的——终端电阻没接、线序接反、波特率不匹配。先排除硬件问题再写软件,能省很多时间。


上一篇:第321篇 嵌入式通信协议SPI/I2C/UART/CAN

下一篇预告:第323篇 EtherCAT工业以太网协议

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐