外观
EtherCAT 双电机+IO 示例
2025-10-29
本示例通过创建一个 EtherCAT Master 实例,完成对 EtherCAT 伺服控制器的初始化配置,使伺服电机控制器工作在CSP同步周期位置模式。将 6060h 设置为 8,驱动器处于 CSP 模式,在周期同步位置模式下,上位控制器将规划好的目标位置 607Ah 周期性同步的方式发送给伺服驱动器,位置、速度、转矩控制由伺服内部完成。
EtherCAT CSP+IO
硬件连接
需要准备硬件:
- 睿擎工业开发平台支持板卡 1 块
- EtherCAT 伺服驱动器一套(推荐
汇川 SV660N或者LICHUAN-LC10E) - EtherCAT IO(SG-ECT-16DI-16DO-NPN)
- 串口调试器、jlink 调试各一套
用网线将伺服控制器 IN 口与开发板 ETH1 网口连接。伺服电机的电源线和编码器线分别接入电源口和 CN3 连接口,IO 接入 IN 口,如图所示:

创建工程点击展开
依次点击 “文件” -> “新建” -> "RT-Thread RuiChing App 项目"。

在弹出新建向导中选择 开发版 、BSP: 、示例 、 调试器/下载器。选择好之后点击 “完成”。

点击 “完成” 后,等待工程创建完成。

创建完成。

构建工程点击展开
单击工程使工程进入 Active-Debug 模式。

点击工具栏上的构建按钮进行工程编译。

构建成功后,会显示构建成功的信息。

固件下载点击展开
固化设备树

固化 APP

控制命令
| 命令 | 功能描述 | 使用示例 |
|---|---|---|
ect_csp_io | 启动 EtherCAT 主站服务 | ect_csp_io |
motor_run | 启动电机运行 | motor_run |
motor_stop | 停止电机运行 | motor_stop |
motor_dir [dir] | 设置电机转动方向( 0 或 1 ) | motor_dir 0 |
核心示例代码
初始化 EtherCAT 主站
- EtherCAT 服务初始化:首先调用
ecat_service_init()函数初始化 EtherCAT 主站服务的核心组件。 - 网络接口配置:指定 EtherCAT 主站使用的网络接口,如 "e1"。
- 主站结构体初始化:通过
ecat_master_init(&csp_master)函数初始化主站结构体。 - 获取从站数量:调用
ecat_slavecount(&csp_master)获取总线上的从站数量。
ethercat_2motor_1io.c
ecat_service_init();
if (ifname)
{
csp_master.nic0 = ifname;
}
err = ecat_master_init(&csp_master);
if (err)
{
rt_kprintf("ethercat master init failed, err:%d\n", err);
return err;
}
slave_counts = ecat_slavecount(&csp_master);
rt_kprintf("Found slaves count:%d\n", slave_counts);配置从站 PDO 映射
- 定义电机 PDO 条目信息
ec_pdo_entry_info_t,包含索引、子索引和数据位长度。 - 定义 IO PDO 条目信息,针对 IO 设备的输入输出配置。
- 定义同步管理器配置
ec_sync_info_t,为电机和 IO 设备分别配置。 - 配置从站结构体
ec_slave_config_t,包含 DC 同步参数和同步管理器配置。
ethercat_2motor_1io.c
// 电机 PDO 配置
static ec_pdo_entry_info_t slave1_output_pdo_entries[] = {
{ 0x6060, 0x00, 8 }, // 6060h(mode)
{ 0x6040, 0x00, 16 }, // 6040h(control)
{ 0x607A, 0x00, 32 }, // 607Ah(dest position)
{ 0x60FF, 0x00, 32 }, // 60FFh(dest speed)
{ 0x6071, 0x00, 16 }, // 6071h(dest torque)
};
static ec_pdo_entry_info_t slave1_input_pdo_entries[] = {
{ 0x603F, 0x00, 16 }, // 603Fh(error)
{ 0x6041, 0x00, 16 }, // 6041h(status)
{ 0x6064, 0x00, 32 }, // 6064h(current postion)
{ 0x606C, 0x00, 32 }, // 606Ch(current speed)
{ 0x6077, 0x00, 16 }, // 6077h(current torque)
};
ec_pdo_info_t slave_pdos[] = {
{ 0x1600, 5, slave1_output_pdo_entries },
{ 0x1a00, 5, slave1_input_pdo_entries },
};
ec_sync_info_t cia402_syncs[] =
{
{ 2, EC_DIR_OUTPUT, 1, &slave_pdos[0], EC_WD_DISABLE },
{ 3, EC_DIR_INPUT, 1, &slave_pdos[1], EC_WD_DISABLE },
};
// IO PDO 配置
static ec_pdo_entry_info_t eio_output1_pdo_entries[] =
{
{ 0x3101, 0x01, 8 },
};
static ec_pdo_entry_info_t eio_output2_pdo_entries[] =
{
{ 0x3101, 0x02, 8 },
};
static ec_pdo_entry_info_t eio_input1_pdo_entries[] =
{
{ 0x3001, 0x01, 8 },
};
static ec_pdo_entry_info_t eio_input2_pdo_entries[] =
{
{ 0x3001, 0x02, 8 },
};
ec_pdo_info_t eio_pdos[] = {
{ 0x1a00, 1, eio_output1_pdo_entries },
{ 0x1a01, 1, eio_output2_pdo_entries },
{ 0x1600, 1, eio_input1_pdo_entries },
{ 0x1601, 1, eio_input2_pdo_entries },
};
ec_sync_info_t eio_syncs[] =
{
{ 0, EC_DIR_OUTPUT, 1, &eio_pdos[0], EC_WD_DISABLE },
{ 1, EC_DIR_OUTPUT, 1, &eio_pdos[1], EC_WD_DISABLE },
{ 2, EC_DIR_INPUT, 2, &eio_pdos[2], EC_WD_DISABLE },
};
static ec_slave_config_t slave_cia402_config;
slave_cia402_config.dc_assign_activate = 0x300;
slave_cia402_config.dc_sync[0].cycle_time = csp_master.main_cycletime_us * 1000;
slave_cia402_config.dc_sync[0].shift_time = 500000;
slave_cia402_config.dc_sync[1].cycle_time = 0;
slave_cia402_config.dc_sync[1].shift_time = 0;
slave_cia402_config.sync = cia402_syncs;
slave_cia402_config.sync_count = sizeof(cia402_syncs) / sizeof(ec_sync_info_t);
static ec_slave_config_t slave_eio_config;
slave_eio_config.dc_assign_activate = 0x300;
slave_eio_config.dc_sync[0].cycle_time = csp_master.main_cycletime_us * 1000;
slave_eio_config.dc_sync[0].shift_time = 500000;
slave_eio_config.dc_sync[1].cycle_time = 0;
slave_eio_config.dc_sync[1].shift_time = 0;
slave_eio_config.sync = eio_syncs;
slave_eio_config.sync_count = sizeof(eio_syncs) / sizeof(ec_sync_info_t);应用从站配置并启动主站
- 遍历所有从站,使用
ecat_slave_info()获取从站信息。 - 通过
vendor_id区分设备类型(电机或 IO)。 - 调用
ecat_slave_config()为每个从站应用对应的配置。 - 调用
ecat_master_start()启动 EtherCAT 主站。 - 使用
ecat_check_state()检查从站是否进入 OPERATIONAL 状态。
ethercat_2motor_1io.c
for(int i = 0; i < slave_counts; i++)
{
ecat_slave_info(&csp_master, i, &info[i]);
if(info[i].vendor_id == 0xee000002) {
// IO 设备配置
ecat_slave_config(&csp_master, i, &slave_eio_config);
}else {
// CIA402 电机配置
ecat_slave_config(&csp_master, i, &slave_cia402_config);
}
}
ecat_master_start(&csp_master);
for(int i = 0; i < slave_counts; i++)
{
ecat_slave_info(&csp_master, i, &info[i]);
}
state = EC_STATE_OPERATIONAL;
err = ecat_check_state(&csp_master, slave_counts - 1, &state, 20000000 * 3);
if (err != RT_EOK)
{
rt_kprintf("Not all slaves reached operational mode.\n");
return err;
}实现电机和 IO 业务逻辑
- 首先更新伺服状态机并检查运行标志,若停止则发送禁用命令。
- 使用
info[slave].outputs和info[slave].inputs获取 PDO 数据指针。 - 通过
vendor_id区分电机和 IO 设备,执行不同的处理逻辑。 - 电机根据控制字状态配置目标位置,IO 设备输出流水灯效果。
ethercat_2motor_1io.c
while (1)
{
if (servo_run == 0)
{
for (size_t slave = 0; slave < slave_counts; slave++)
{
rmap = (struct rpdo_csp *)(info[slave].outputs);
tmap = (struct tpdo_csp *)(info[slave].inputs);
if (info[slave].vendor_id != 0xee000002)
{
servo_switch_op(rmap, tmap);
rmap->control_word = 0x2;
}
}
goto stop;
}
for (size_t slave = 0; slave < slave_counts; slave++)
{
rmap = (struct rpdo_csp *)(info[slave].outputs);
tmap = (struct tpdo_csp *)(info[slave].inputs);
if (info[slave].vendor_id != 0xee000002)
{
servo_switch_op(rmap, tmap);
if (rmap->control_word == 7)
{
rmap->mode_byte = 0x8;
rmap->dest_pos = tmap->cur_pos;
}
if (rmap->control_word == 0xf)
{
rmap->dest_pos = tmap->cur_pos;
if (servo_dir == 0)
{
rmap->dest_pos -= 1000;
}
else
{
rmap->dest_pos += 1000;
}
}
}
else
{
// IO 设备流水灯效果
if (rt_tick_get() - last_ms > RT_TICK_PER_SECOND / 4)
{
static uint8_t index = 0;
uint16_t *out = (uint16_t *)rmap;
last_ms = rt_tick_get();
*out = (0x01 << index);
index++;
if (index >= 16)
index = 0;
}
}
}
stop:
rt_thread_mdelay(10);
}示例运行
初始化 EtherCAT 主站
msh > ect_csp_io启动电机运行
msh > motor_run改变电机方向
msh > motor_dir 0/1停止电机
msh > motor_stop使用 IDE 调试并运行程序,初始化完 EtherCAT 主站后,在终端输入motor_run 运行电机,可以观察到电机旋转。EtherCAT 示例运行后,电机会顺时针旋转。驱动器风扇会开启,面板显示88rn字符。
在终端输入motor_stop 可以停止电机。
在终端输入motor_dir 0/1 可以改变电机方向。
