3、通信协议:脉冲方向控制、CANopen协议、EtherCAT协议、Modbus协议

做机器人运动控制,说白了就是跟电机「对话」。你给它下指令,它告诉你状态。这个对话怎么进行?靠的就是通信协议。

我入行那会儿,用的最多的就是脉冲方向控制。简单粗暴,一根线发脉冲,一根线定方向。后来项目越来越复杂,多轴同步、实时性要求高了,才开始接触CANopen、EtherCAT这些。嗯,今天就把这四种协议掰开揉碎了讲清楚。

运动控制通信协议 脉冲方向控制 CANopen协议 EtherCAT协议 Modbus协议 简单、低成本 适合单轴/低速 多主站、可靠 适合分布式系统 高速、实时 适合多轴同步 通用、易集成 适合PLC/HMI 选型口诀: 单轴低速用脉冲,多轴同步上EtherCAT 分布式系统CANopen,通用集成找Modbus

3.1 脉冲方向控制——最朴素的对话方式

脉冲方向控制,也叫Pulse/Direction控制。原理特别简单:控制器发一串脉冲,电机就走一步。脉冲的频率决定速度,脉冲的数量决定位置。方向嘛,就靠另一根线的电平高低来定。

我记得刚毕业那会儿,调试一个两轴平台。上位机发脉冲,驱动器接收,电机就转了。那时候觉得,这玩意儿真直接,真爽。

核心参数:

  • 脉冲频率:决定电机转速,单位Hz
  • 脉冲数量:决定电机位置,单位个
  • 方向信号:高电平正转,低电平反转(或相反,看驱动器设置)

举个例子。你有一个步进电机,驱动器设置为1000脉冲/圈。你想让电机转5圈,那就发5000个脉冲。想让电机转快点,就把脉冲频率从1kHz提到10kHz。

// 伪代码示例:脉冲方向控制
void move_motor(int steps, int direction, int frequency) {
    set_direction_pin(direction);  // 设置方向
    for (int i = 0; i < steps; i++) {
        pulse_pin_high();
        delay_us(500000 / frequency);  // 根据频率调整脉冲宽度
        pulse_pin_low();
        delay_us(500000 / frequency);
    }
}

⚠️ 注意:脉冲频率不是越高越好。频率太高,电机可能丢步。我曾经在一个项目中把频率调到200kHz,结果电机直接「抖」起来了,根本走不动。后来降到50kHz才稳定。

脉冲方向控制的优点很明显:简单、便宜、兼容性好。几乎所有的步进驱动器和伺服驱动器都支持。缺点也很突出:占用IO口多,多轴同步困难,没有反馈信息。

你想想看,如果你要做6轴机器人,每个轴需要2根线(脉冲+方向),那就是12根线。线多了,干扰就来了。而且你没法知道电机实际走到了没有,全靠开环。

3.2 CANopen协议——分布式系统的老大哥

CANopen是基于CAN总线的应用层协议。CAN总线本身是德国Bosch公司发明的,最早用在汽车上。后来工业自动化看上了它,就搞出了CANopen。

我个人习惯把CANopen理解成一个「邮局系统」。每个设备都有一个地址(节点ID),大家通过总线收发「信件」(报文)。信件有优先级,紧急的先发。

💡 小知识:CANopen的报文类型主要有四种:

  • NMT:网络管理报文,控制设备状态(启动、停止、复位)
  • PDO:过程数据对象,传输实时数据(位置、速度、电流)
  • SDO:服务数据对象,传输配置参数(增益、限位、加速度)
  • SYNC:同步报文,用于多轴同步

我在做一个多轴协作机器人项目时,用了CANopen。6个关节,每个关节一个驱动器,全部挂在一条CAN总线上。用SYNC报文同步,所有轴同时执行运动指令。效果还不错,同步误差在1ms以内。

// CANopen SDO 读写示例(简化)
// 读取驱动器对象 0x6060(操作模式)
uint8_t read_sdo(uint16_t node_id, uint16_t index, uint8_t subindex) {
    CAN_message_t msg;
    msg.id = 0x600 + node_id;  // 发送SDO请求
    msg.data[0] = 0x40;        // 读命令
    msg.data[1] = index & 0xFF;
    msg.data[2] = (index >> 8) & 0xFF;
    msg.data[3] = subindex;
    msg.data[4] = 0x00;
    msg.data[5] = 0x00;
    msg.data[6] = 0x00;
    msg.data[7] = 0x00;
    msg.len = 8;
    can_send(&msg);
    
    // 等待响应...
    // 响应ID为 0x580 + node_id
}

⚠️ 注意:CANopen的波特率一般设置125kbps、250kbps或500kbps。总线长度越长,波特率要越低。我曾经在一条50米的总线上用500kbps,结果丢包严重。降到250kbps就稳了。

CANopen的优点是可靠性高、支持多主站、有完整的设备描述文件(EDS)。缺点是实时性不如EtherCAT,带宽有限(最高1Mbps)。

3.3 EtherCAT协议——实时性的王者

EtherCAT是德国Beckhoff公司开发的实时以太网协议。它的核心思想是「飞读飞写」:数据帧经过每个从站时,从站直接读取或写入数据,延迟只有纳秒级。

我第一次用EtherCAT时,真的被震撼到了。100个轴同步,抖动误差小于1微秒。这在以前用脉冲控制时想都不敢想。

EtherCAT的关键特性:

  • 分布式时钟:所有从站时钟同步,精度<1μs
  • 帧处理技术:数据帧在从站内部直接处理,无需CPU干预
  • 热连接:支持带电插拔(需硬件支持)
  • 拓扑灵活:支持线型、星型、树型、环型

EtherCAT的报文结构很有意思。一个以太网帧里可以包含多个子报文,每个子报文对应一个从站或一组从站。主站发一个帧,所有从站都处理完了,然后帧再返回主站。

// EtherCAT 从站配置示例(基于SOEM库)
#include "soem/ethercat.h"

int main() {
    // 初始化
    ec_init("eth0");
    
    // 扫描从站
    ec_config_init(FALSE);
    
    // 配置PDO映射
    ec_config_map(&IOmap);
    
    // 配置分布式时钟
    ec_configdc();
    
    // 进入运行状态
    ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE);
    
    // 循环发送/接收数据
    while(1) {
        ec_send_processdata();
        ec_receive_processdata(EC_TIMEOUTRET);
        
        // 读取从站1的位置
        int32_t pos = *(int32_t*)(ec_slave[1].inputs);
        
        // 写入从站2的速度
        *(int32_t*)(ec_slave[2].outputs) = 1000;
    }
}

💡 经验之谈:EtherCAT的线缆质量很重要。我遇到过因为用了劣质网线,导致通信时断时续。后来全部换成CAT6屏蔽网线,问题解决。另外,EtherCAT的从站数量不是无限的,一般建议不超过200个。

EtherCAT的缺点也很明显:成本高(需要专用从站芯片)、配置复杂、对主站硬件有要求(需要网卡支持)。但如果你做的是高端多轴机器人,EtherCAT几乎是唯一选择。

3.4 Modbus协议——工业界的通用语言

Modbus是Modicon公司1979年发明的,老古董了。但你别小看它,至今还在大量使用。为什么?因为它简单、开放、几乎所有设备都支持。

Modbus有两种传输模式:RTU(二进制)和ASCII(文本)。RTU效率高,ASCII容易调试。我个人习惯用RTU,数据紧凑,传输快。

Modbus常用功能码:

功能码名称说明
0x03读保持寄存器读取多个寄存器的值
0x06写单个寄存器写入一个寄存器的值
0x10写多个寄存器写入多个寄存器的值
0x01读线圈读取开关量输出
0x05写单个线圈写入一个开关量输出

我在调试一个AGV小车时,用了Modbus RTU控制驱动器。PLC通过RS485发指令,驱动器响应。虽然速度不快(115200bps),但胜在稳定。小车跑了两年,没出过通信问题。

// Modbus RTU 读取驱动器速度示例
// 设备地址:0x01,读取寄存器地址:0x2000(速度值)
uint8_t modbus_read_request[] = {
    0x01,       // 从站地址
    0x03,       // 功能码:读保持寄存器
    0x20, 0x00, // 起始地址高8位、低8位
    0x00, 0x01, // 寄存器数量
    0x84, 0x0A  // CRC校验(低字节在前)
};

// 响应示例(假设速度值为1500 RPM)
uint8_t modbus_read_response[] = {
    0x01,       // 从站地址
    0x03,       // 功能码
    0x02,       // 数据字节数
    0x05, 0xDC, // 数据:0x05DC = 1500
    0x??, 0x??  // CRC校验
};

⚠️ 注意:Modbus没有同步机制,不适合多轴同步控制。如果你需要多个电机同时动作,Modbus不是好选择。另外,RS485总线需要终端电阻,否则信号反射会导致通信错误。我曾经忘了加终端电阻,调试了一整天才发现。

Modbus的优点:通用性强、成本低、调试方便。缺点:速度慢、不支持实时同步、主从架构限制了灵活性。

3.5 如何选择?

说了这么多,到底用哪个?我个人的建议是这样的:

  • 单轴或两轴,精度要求不高:用脉冲方向控制。成本最低,调试最快。
  • 多轴分布式系统,实时性要求一般:用CANopen。可靠、成熟、性价比高。
  • 多轴高速同步,实时性要求极高:用EtherCAT。虽然贵,但值得。
  • 与PLC或HMI通信,数据量不大:用Modbus。兼容性好,几乎不会出问题。

💡 最后说一句:没有最好的协议,只有最合适的。选型时考虑三个因素:成本、实时性、生态兼容性。别盲目追求高端,也别为了省钱牺牲性能。

好了,通信协议这块就聊到这儿。下一章我们聊聊电机选型,那又是另一个有意思的话题。


专注资料整理