首页 / 资讯中心 / 文章详情

EtherCAT与CAN总线破界融合:协议解析与工程实践

EtherCAT与CAN总线破界融合:协议解析与工程实践 ★ FEATURED ARTICLE
1. 从标题拆解这个项目的核心命题“高速互联 总线破界”这个说法第一次看到的时候我琢磨了好一会儿。它其实点出了一个在工业控制和嵌入式系统圈子里被讨论了很多年、但始终没有标准答案的问题当实时以太网和传统现场总线在同一套系统里共存时怎么让它们真正“破界”而不是简单地堆在一起各跑各的。EtherCAT 和 CAN 是两种定位差异很大的通讯协议。EtherCAT 追求的是微秒级的循环周期和极低的抖动典型应用是运动控制、多轴同步、高速数据采集CAN 则更像一个皮实耐用的老黄牛成本低、布线简单、抗干扰强在汽车电子、工程机械、楼宇自动化里活了几十年依然不可替代。很多实际项目里一套设备既要跑 EtherCAT 的高实时轴控又要接一堆 CAN 的传感器和执行器这时候通讯协议的深度理解和融合设计就成了绕不过去的坎。这篇内容适合谁看如果你正在做多协议网关、运动控制器、工业机器人或者产线改造项目需要在 EtherCAT 和 CAN 之间做数据桥接那接下来的内容应该能帮你少走一些弯路。如果你只是刚接触现场总线想搞清楚这两种协议到底差在哪、为什么不能随便替换我也会从最基础的地方讲起。整篇内容基于我在几个模拟项目中的实际调试经验结合协议本身的机制来展开不堆砌手册上的原话尽量说人话。2. 两种协议的底层逻辑与设计哲学2.1 EtherCAT 为什么能做到微秒级响应EtherCAT 的全称是 Ethernet for Control Automation Technology它的核心思路和普通以太网完全不一样。普通以太网是“每个节点收到一整帧解析完再转发”而 EtherCAT 用的是“飞读飞写”processing on the fly机制。主站发一帧数据从站芯片在数据帧经过的瞬间就把该读的读走、该写的写进去不需要把整帧缓存下来再处理。这一下就把每个节点的处理延迟从几十微秒压到了纳秒级。打个比方普通以太网像快递员把包裹送到每家每户、等收件人签收完再走EtherCAT 更像一列高速列车每个站台在列车经过的瞬间完成上下客列车根本不停。这个机制决定了 EtherCAT 的循环周期可以做到 100 微秒甚至更低而且抖动极小。对于多轴同步控制来说这意味着所有轴的指令可以在同一个时钟节拍下更新同步误差控制在纳秒级。但 EtherCAT 也有它的“脾气”。它必须用专用的从站控制芯片比如 ET1100、ET1200 或者集成在 MCU 里的 ESC 模块普通以太网控制器做不了从站。主站这边通常用标准网卡加实时补丁比如在 Linux 上跑 IgH EtherCAT Master 或者 Xenomai 实时内核对操作系统的实时性要求很高。如果你在 Windows 上跑 EtherCAT 主站基本只能做做测试真上产线还是得靠实时 Linux 或者带实时核的 PLC。2.2 CAN 总线的非破坏性仲裁与错误处理CAN 总线诞生于 1980 年代博世把它设计出来就是为了在汽车这种电磁环境恶劣、节点多、线束长的场景下可靠通讯。它的核心机制有两个特别值得说非破坏性仲裁和强大的错误处理。非破坏性仲裁的意思是当多个节点同时想发数据时它们会一边发一边听。CAN 的显性位逻辑 0会覆盖隐性位逻辑 1所以 ID 数值越小显性位越多的报文优先级越高。关键是仲裁失败的节点不会丢失数据它会自动退让等总线空闲了再重发。这个过程不需要软件干预完全是 CAN 控制器硬件完成的。这就保证了高优先级报文比如刹车信号永远能及时发出去低优先级报文比如车窗状态晚一点也没关系。错误处理这块CAN 有错误计数器和节点状态机。每个节点维护发送错误计数和接收错误计数计数超过一定阈值就进入“错误被动”状态再严重就“总线关闭”自动退出总线避免影响其他人。这个机制让 CAN 在强干扰环境下依然能保持整体通讯的稳定性坏掉的节点不会拖垮整条总线。但 CAN 的短板也很明显带宽低经典 CAN 最高 1 MbpsCAN FD 可以到 5 Mbps 甚至更高、单帧数据少经典 CAN 8 字节CAN FD 64 字节、没有统一的时钟同步机制。所以它适合传状态、命令、传感器读数不适合传大量实时数据或者做高精度同步。2.3 为什么不能简单替换经常有人问既然 EtherCAT 这么快为什么不把所有 CAN 设备都换成 EtherCAT答案很简单成本和场景不匹配。一个 CAN 温度传感器可能几块钱换成 EtherCAT 版本可能要几十甚至上百块而且布线、供电、配置都更复杂。一条产线上可能有几十个 CAN 节点全换掉成本翻几倍但实际需要的实时性根本用不到 EtherCAT 那个级别。反过来运动控制轴如果换成 CAN同步精度和循环周期都达不到要求多轴插补会抖得没法看。所以现实中的方案往往是两者共存EtherCAT 管高速同步轴控CAN 管低速状态采集和辅助设备中间用一个网关或者控制器做协议转换和数据映射。这个“破界”的过程才是真正考验设计功力的地方。3. 协议融合的架构设计与关键决策3.1 网关方案 vs 主控集成方案把 EtherCAT 和 CAN 弄到一套系统里最直接的做法是加一个协议网关。网关一边接 EtherCAT 从站接口一边接 CAN 收发器内部做数据映射。主站通过 EtherCAT 周期性地读写网关的输入输出数据网关再把数据翻译成 CAN 报文发出去或者把 CAN 收到的数据塞进 EtherCAT 的过程数据区。这个方案的好处是解耦。EtherCAT 主站不需要关心 CAN 那边的细节网关固件把协议差异全吃掉了。换 CAN 设备或者改波特率只要改网关配置就行主站程序不用动。缺点是多了个硬件成本增加而且网关本身会引入额外的延迟。如果 CAN 那边数据量不大、实时性要求不高这个延迟通常可以接受。另一种做法是把 CAN 控制器直接集成到 EtherCAT 主站控制器里。比如用一块带 EtherCAT 主站协议栈和 CAN 控制器的工控板在同一个 CPU 上跑两个协议栈通过共享内存做数据交换。这个方案延迟更低、成本更省但软件复杂度高两个协议栈的实时性要协调好否则 CAN 的突发流量可能影响 EtherCAT 的循环周期。我个人的经验是如果 CAN 节点数量少比如少于 10 个、数据量小、实时性要求一般优先考虑主控集成方案省硬件省空间。如果 CAN 节点多、数据量大、或者需要热插拔和独立维护网关方案更稳妥出了问题也好排查。3.2 数据映射表的设计原则不管用哪种方案核心都是数据映射。EtherCAT 的过程数据区是一块固定大小的内存每个从站有对应的输入和输出偏移。CAN 那边是一堆报文 ID 和数据字节。映射表要做的就是定义“哪个 CAN 报文的哪几个字节对应 EtherCAT 过程数据区的哪个偏移”。设计映射表的时候有几个原则。第一按更新频率分组。高频更新的数据比如每 1 毫秒更新一次的传感器读数放在一起低频数据比如每 100 毫秒更新的状态字放另一块这样 EtherCAT 主站可以按不同周期分别处理不用为了几个慢速数据拖累整个循环。第二预留扩展空间。过程数据区不要塞满留 20% 左右的余量以后加设备或者改协议不用重新规划整个映射。第三字节对齐要注意。CAN 报文的数据长度不固定映射到 EtherCAT 过程数据区时尽量按字节或字对齐避免跨边界读写带来的额外处理。还有一个容易被忽略的点字节序。EtherCAT 和 CAN 在字节序上通常都是小端模式但有些 CAN 设备厂商会按大端发送多字节数据。映射的时候一定要确认清楚否则一个 16 位的温度值可能高字节低字节颠倒读出来差 256 倍。我就在一个模拟项目里踩过这个坑调试了半天以为是传感器坏了最后发现是字节序没对上。3.3 实时性预算与周期分配EtherCAT 主站的循环周期是系统实时性的基准。假设你设了 1 毫秒的周期那每个周期内要完成读取所有从站输入、执行控制算法、写入所有从站输出、处理 CAN 数据交换。这些都要在 1 毫秒内做完还要留出余量给操作系统调度和网络抖动。CAN 那边的波特率和报文数量决定了 CAN 总线的负载率。经典 CAN 在 500 kbps 下一帧标准报文大约 130 微秒左右取决于仲裁和位填充。如果总线上有 20 个报文要发每个周期发一轮那就是 2.6 毫秒已经超过 1 毫秒的 EtherCAT 周期了。这时候要么降低 CAN 报文的发送频率要么提高 CAN 波特率比如上 CAN FD要么把 CAN 数据分成多个 EtherCAT 周期轮流更新。我的做法是先在纸上算一笔账列出所有 CAN 报文的 ID、长度、发送周期算出总线负载率。一般建议 CAN 总线负载率不要超过 50%留一半余量给突发和错误重传。然后根据 EtherCAT 周期和 CAN 负载率决定哪些数据每个周期更新、哪些隔几个周期更新。这个预算做好了后面调试会顺很多。4. 实操配置与调试过程实录4.1 EtherCAT 主站环境搭建要点在 Linux 上跑 EtherCAT 主站我一般用 IgH EtherCAT Master。安装过程不算复杂但有几个地方容易出问题。首先是网卡选择不是所有网卡都支持 IgH 的实时驱动。Intel 的 e1000e、igb、82574 这些系列兼容性比较好Realtek 的网卡经常出问题。选网卡的时候最好查一下 IgH 的兼容列表或者直接用 Intel 的服务器网卡。编译内核模块的时候要确保内核版本和 IgH 版本匹配。IgH 2.5 之后的版本对 Linux 4.x 和 5.x 内核支持比较好但如果你用的是比较新的内核比如 6.x可能需要打一些补丁。编译前先确认内核头文件装好了make modules和make install之后用depmod更新模块依赖。配置主站的时候ethercat.conf里要指定主站网卡的 MAC 地址。如果机器上有多个网卡一定要确认哪个口接 EtherCAT 从站别配错了。启动主站用ethercat start然后用ethercat slaves看能不能扫到从站。如果扫不到先检查网线、从站供电、EEPROM 配置再检查主站日志dmesg | grep EtherCAT。注意IgH 主站启动后那块网卡就不能再当普通网卡用了。如果你需要同时上网和跑 EtherCAT至少得有两块网卡一块给系统一块给 EtherCAT。4.2 CAN 接口配置与波特率计算Linux 下用 SocketCAN 操作 CAN 接口比较方便。加载模块modprobe can、modprobe can_raw、modprobe vcan虚拟 CAN 用于测试然后ip link set can0 type can bitrate 500000设置波特率ip link set can0 up启动接口。波特率计算这里有个细节CAN 的位时间分成同步段、传播段、相位缓冲段1和相位缓冲段2。波特率 1 / (位时间)。以 500 kbps 为例位时间是 2 微秒。如果 CAN 控制器时钟是 8 MHz那一个位时间就是 16 个时钟周期。这 16 个周期要分配到各个段里通常同步段 1 个周期、传播段 4 个、相位缓冲段1 6 个、相位缓冲段2 5 个加起来 16。采样点一般在 75% 到 87.5% 之间上面这个分配采样点在 (146)/16 68.75%稍微偏早可以调整成传播段 3、相位缓冲段1 7、相位缓冲段2 5采样点变成 (137)/16 68.75%还是偏早。再调成传播段 2、相位缓冲段1 8、相位缓冲段2 5采样点 (128)/16 68.75%。要提高到 75%可以传播段 2、相位缓冲段1 9、相位缓冲段2 4采样点 (129)/16 75%。实际配置的时候SocketCAN 的bitrate参数会自动算这些段但如果你用ip link set can0 type can bitrate 500000 sample-point 0.75可以手动指定采样点。采样点设对了长线缆和多个节点的时候通讯稳定性会好很多。4.3 数据桥接的代码实现思路假设我们用主控集成方案在同一个 Linux 系统上跑 IgH EtherCAT 主站和 SocketCAN。数据交换可以用共享内存加环形缓冲区的方式。EtherCAT 主站周期任务里从过程数据区读出 CAN 要发的数据写进环形缓冲区另一个线程从缓冲区取出数据通过 SocketCAN 发出去。反过来SocketCAN 收到的数据写进另一个环形缓冲区EtherCAT 周期任务从缓冲区读出来写进过程数据区。环形缓冲区的好处是读写解耦EtherCAT 周期任务不会被 CAN 发送阻塞。但要注意缓冲区大小和溢出处理。如果 CAN 发送比 EtherCAT 周期慢缓冲区会堆积堆到满了就得丢最老的数据或者覆盖。我一般设两个缓冲区一个用于 EtherCAT 到 CAN 方向一个用于 CAN 到 EtherCAT 方向每个缓冲区大小按最大突发数据量乘 2 来设。代码结构上EtherCAT 周期任务用ecrt_master_receive、ecrt_domain_process、ecrt_domain_queue、ecrt_master_send这套标准流程。CAN 发送线程用write系统调用往can0写数据。两个线程之间用互斥锁或者无锁队列同步。如果对实时性要求高CAN 发送线程可以设成实时优先级但不要比 EtherCAT 周期任务高否则 CAN 突发会打断 EtherCAT 循环。// 简化的 EtherCAT 周期任务伪代码 while (running) { ecrt_master_receive(master); ecrt_domain_process(domain); // 从过程数据区读 CAN 要发的数据 uint8_t *can_tx_data ecrt_domain_data(domain) CAN_TX_OFFSET; ring_buffer_write(can_tx_ring, can_tx_data, CAN_TX_SIZE); // 把 CAN 收到的数据写进过程数据区 uint8_t *can_rx_data ecrt_domain_data(domain) CAN_RX_OFFSET; ring_buffer_read(can_rx_ring, can_rx_data, CAN_RX_SIZE); ecrt_domain_queue(domain); ecrt_master_send(master); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, next_wake, NULL); next_wake.tv_nsec CYCLE_NS; }4.4 调试工具与排查手段EtherCAT 这边ethercat命令行工具很好用。ethercat slaves看从站列表ethercat pdos看过程数据映射ethercat sdos看服务数据对象ethercat graph可以画拓扑图。如果循环周期不稳定用ethercat master看主站状态和丢帧计数。CAN 这边candump can0可以实时打印总线上的报文cansend can0 123#11223344可以手动发一帧。canbusload can0500000可以算总线负载率。如果怀疑某个节点发得太频繁用candump加过滤candump can0,123:7FF只看特定 ID。跨协议调试的时候我一般先在 EtherCAT 主站里把 CAN 数据映射到过程数据区然后用ethercat upload或者直接在代码里打印过程数据区的值确认 CAN 数据确实进来了。再反过来在 CAN 总线上用candump看 EtherCAT 写出去的数据有没有正确发到 CAN。两边都对上了再联调控制逻辑。实操心得调试初期先把 EtherCAT 周期设大一点比如 10 毫秒等两边数据都通了再逐步降到 1 毫秒甚至更低。一上来就设极限周期出了问题很难判断是协议问题还是实时性问题。5. 常见问题与排查技巧实录5.1 EtherCAT 从站扫不到或频繁掉线这是最常见的问题。先看物理层网线是不是超五类以上、接头有没有做好、从站供电是否正常。EtherCAT 对网线质量比普通以太网敏感劣质网线或者水晶头压接不良会导致从站时好时坏。我遇到过好几次都是网线问题换了成品线就好了。如果物理层没问题检查从站 EEPROM 配置。有些从站模块出厂时 EEPROM 是空的需要先用配置工具写入正确的 XML 描述文件。没有 EEPROM 或者 EEPROM 内容不对主站识别不了从站类型就会报错。还有一种情况是从站数量多、线缆长信号衰减导致末端从站通讯不稳定。EtherCAT 标准说两个从站之间最长 100 米但实际用普通网线跑 50 米以上就可能出问题。这时候要么加中继器要么缩短距离要么换更好的线缆。5.2 CAN 总线负载率过高导致丢帧CAN 总线负载率超过 70% 之后报文延迟会明显增加仲裁失败的概率也上升。如果发现丢帧先用canbusload算一下当前负载率。如果确实高了有几个办法提高波特率比如从 500 kbps 升到 1 Mbps或者上 CAN FD、减少报文数量合并一些低频报文、降低发送频率比如从 10 毫秒改成 20 毫秒。还有一个隐蔽的问题某些 CAN 设备在错误状态下会疯狂重发把总线负载率拉满。用candump看有没有大量相同 ID 的报文反复出现如果有检查那个设备的错误计数器可能是终端电阻不对或者线缆短路。终端电阻也是老生常谈的问题。CAN 总线两端各需要一个 120 欧姆终端电阻中间节点不需要。如果电阻缺失或者阻值不对通讯距离短的时候可能还能凑合距离一长或者节点一多就各种奇怪问题。用万用表量一下 CAN_H 和 CAN_L 之间的电阻正常应该是 60 欧姆左右两个 120 欧姆并联。5.3 数据映射错位或数值异常映射错位通常有几个原因偏移量算错、字节序不对、数据类型不匹配。偏移量算错最常见尤其是过程数据区里既有输入又有输出、还有不同从站的时候。我一般用表格把每个从站的输入输出偏移、每个 CAN 报文的映射位置都列出来对照着检查。字节序问题前面提过多字节数据一定要确认两边一致。数据类型不匹配也容易出问题比如 CAN 那边发的是有符号 16 位整数EtherCAT 这边按无符号读负数就变成大正数了。映射的时候把数据类型标注清楚代码里用对应的类型转换。还有一种情况是 CAN 报文长度和映射表里写的不一致。比如映射表里写的是 8 字节实际设备只发 4 字节那后面 4 个字节就是垃圾数据。调试的时候用candump确认实际报文长度再改映射表。5.4 常见问题速查表现象可能原因排查手段解决方向EtherCAT 从站扫不到网线/供电/EEPROM换线、量电压、看主站日志修复物理层或写入 EEPROMEtherCAT 周期抖动大网卡不兼容/系统负载高看丢帧计数、关后台进程换兼容网卡、优化实时性CAN 丢帧负载率高/终端电阻不对canbusload、量电阻降负载、加终端电阻CAN 错误帧多干扰/接地问题candump 看错误帧检查屏蔽和接地数据映射错位偏移/字节序/类型对照映射表逐字节检查修正映射或转换类型数值跳变字节序/符号位打印原始字节统一字节序和类型避坑技巧每次改完映射表或者协议配置先用手动发送和接收验证一遍确认数据通了再跑自动流程。我吃过亏改完直接跑整机结果一个字节序问题查了一下午。6. 性能优化与扩展思路6.1 降低 EtherCAT 循环抖动的几个手段EtherCAT 主站的循环抖动主要来自操作系统调度和网络中断处理。在 Linux 上可以用isolcpus把某个 CPU 核隔离出来专门跑 EtherCAT 周期任务其他任务不往这个核上调度。中断亲和性也要设把网卡中断绑到另一个核上避免中断处理打断周期任务。IgH 主站支持ecrt_master_set_send_interval和ecrt_master_sync这些同步机制。如果从站支持分布式时钟DC一定要启用 DC 同步让所有从站的时钟和主站对齐。DC 同步做好之后多轴同步误差可以控制在几十纳秒以内。还有一点容易被忽略EtherCAT 周期任务里的代码要尽量精简。控制算法如果复杂可以拆成多个周期执行不要在一个周期里做太多事情。内存分配、文件操作、打印日志这些都不要放在周期任务里否则一次系统调用就可能让周期抖动几百微秒。6.2 CAN FD 的升级考量如果 CAN 总线负载率实在降不下来可以考虑升级到 CAN FD。CAN FD 的数据段波特率可以到 5 Mbps 甚至更高单帧数据从 8 字节扩展到 64 字节。同样的数据量CAN FD 的总线占用时间可以缩短到经典 CAN 的几分之一。但升级 CAN FD 不是换个收发器就行。CAN 控制器要支持 FD从站设备也要支持。总线上如果有经典 CAN 和 CAN FD 混用需要控制器支持混合模式否则 FD 帧会被经典 CAN 节点当成错误帧。升级之前先确认所有节点都支持 FD或者至少能容忍 FD 帧。CAN FD 的波特率配置比经典 CAN 复杂数据段和仲裁段可以设不同波特率。仲裁段保持 500 kbps 兼容经典 CAN数据段升到 2 Mbps 或 5 Mbps。采样点也要分别设置数据段因为速率高采样点通常设得靠后一些比如 80%。6.3 多协议扩展的可能性EtherCAT 和 CAN 的融合只是多协议系统的一个例子。实际项目里还可能遇到 EtherCAT 加 Modbus、EtherCAT 加 Profinet、CAN 加 LIN 这些组合。设计思路是类似的先明确每个协议的实时性要求和数据特征再决定用网关还是主控集成然后设计数据映射和周期分配。如果协议种类多可以考虑用支持多协议栈的工业通讯控制器或者用 FPGA 做协议转换。FPGA 的好处是延迟极低、并行处理能力强但开发难度大、成本高。对于大多数项目来说用带多协议支持的 ARM 工控板加实时 Linux 就够了。扩展的时候要注意协议之间的时钟同步。如果 EtherCAT 和 CAN 的数据需要在时间上对齐可以用 EtherCAT 的分布式时钟作为基准CAN 那边的时间戳按这个基准来校准。如果对时间对齐要求不高各自按自己的周期跑就行。7. 几个实际项目中的经验教训我在一个模拟的多轴运动控制项目里用 EtherCAT 控制 6 个伺服轴同时用 CAN 接 12 个限位开关和 4 个温度传感器。一开始把 CAN 数据全部映射到 EtherCAT 过程数据区每个周期都更新。结果发现 EtherCAT 周期从 1 毫秒抖到了 1.5 毫秒查了半天发现是 CAN 发送线程偶尔会阻塞因为 SocketCAN 的发送缓冲区满了。后来改成 CAN 数据分频更新限位开关每 2 个 EtherCAT 周期更新一次温度传感器每 100 个周期更新一次。CAN 发送线程的优先级也调低了并且加了发送失败重试机制。改完之后 EtherCAT 周期稳定在 1 毫秒抖动在 20 微秒以内。另一个教训是关于终端电阻的。一个模拟项目里 CAN 总线只有 3 个节点线缆不到 2 米我觉得这么短的距离不接终端电阻应该也没事。结果调试的时候偶尔丢帧查了两天才发现是终端电阻的问题。接上 120 欧姆电阻之后丢帧率直接降到零。所以不管线缆多短终端电阻该接还得接。还有一个关于字节序的坑。一个 CAN 压力传感器发的是大端格式的 32 位浮点数我按小端解析读出来的压力值一直是错的。后来用candump把原始字节打出来对照传感器手册才发现字节序反了。在代码里加了个字节交换函数就好了。这件事之后我养成了一个习惯拿到任何 CAN 设备先用candump看原始数据确认字节序和数据类型再写解析代码。最后说一个关于实时性的体会。EtherCAT 主站的实时性不仅取决于软件还取决于硬件。同样的代码在普通台式机上跑和在带实时核的工控机上跑抖动可能差一个数量级。如果项目对实时性要求高不要在硬件上省钱。一块好的工控板加 Intel 网卡比在普通 PC 上折腾实时补丁要省心得多。
阅读完成 · 觉得有帮助?
咨询建站