迁移EtherCAT机器人程序时ecrt_master_activate函数无响应求助
将基于EtherCAT系统的机器人程序迁移至另一台电脑,已安装rt kernel、Xenomai及EtherLab构建的EtherCAT主站。连接所有电机驱动器后启动通信程序,初始化主站、扫描从站步骤均正常,但调用ecrt_master_activate函数时程序陷入无限等待,无法通过ctrl+c、kill命令终止进程。通过htop查看显示进程处于等待磁盘I/O状态,添加日志排查后发现该函数未被执行(未打印函数内的日志信息)。
调用ecrt_master_activate的代码
bool ECRT_Master::Activate() // ecrt_master_activate { std::cout << "m_pmaster" << m_pMaster << std::endl; int check; check = ecrt_master_activate(m_pMaster); std::cout << "check" << check << std::endl; return check ? true : false; }
EtherLab提供的ecrt_master_activate函数实现
int ecrt_master_activate(ec_master_t *master) { printf("function inside"); ec_ioctl_master_activate_t io; printf("io"); int ret; printf("before ioctl"); ret = ioctl(master->fd, EC_IOCTL_ACTIVATE, &io,20); printf("after ioctl"); if (EC_IOCTL_IS_ERROR(ret)) { fprintf(stderr, "Failed to activate master: %s\n", strerror(EC_IOCTL_ERRNO(ret))); return -EC_IOCTL_ERRNO(ret); } master->process_data_size = io.process_data_size; if (master->process_data_size) { #ifdef USE_RTDM /* memory-mapping was already done in kernel. The user-space addess is * provided in the ioctl data. */ master->process_data = io.process_data; #else master->process_data = mmap(0, master->process_data_size, PROT_READ | PROT_WRITE, MAP_SHARED, master->fd, 0); if (master->process_data == MAP_FAILED) { fprintf(stderr, "Failed to map process data: %s\n", strerror(errno)); master->process_data = NULL; master->process_data_size = 0; return -errno; } #endif // Access the mapped region to cause the initial page fault master->process_data[0] = 0x00; } return 0; }
程序最后部分日志
Commservo pass1 CommFaultReset pass1 CommTargetCurrent pass1 CommOperationMode pass1 CommPositionSpeed pass1 CSlave.cpp [Initialize] : Slave (6) Initialize.. Status [1] CSlave.cpp [ConfigPdos] : Slave (6) Set Slave PDO Entry.. CSlave.cpp [ConfigPdos] : Slave (6) ConfigPdos.. pSlave [0x55aa486c8f00] pSyncManager [0x55aa486cb8f0] CSlave.cpp [Initialize] : Slave (7) Initialize.. Commservo pass1 CommFaultReset pass1 CommTargetCurrent pass1 CommOperationMode pass1 CommPositionSpeed pass1 CSlave.cpp [Initialize] : Slave (7) Initialize.. Status [1] CSlave.cpp [ConfigPdos] : Slave (7) Set Slave PDO Entry.. CSlave.cpp [ConfigPdos] : Slave (7) ConfigPdos.. pSlave [0x55aa486c9080] pSyncManager [0x55aa486cba90] CSlaveManager.cpp [Run] : Run Thread... CMaster.cpp [Activate] : Activate... m_pmaster0x55aa486c82d0
从现象看,进程卡在ecrt_master_activate调用入口,且处于不可中断的I/O等待状态,说明问题出在用户态到内核态的调用路径上,以下是针对性排查和解决步骤:
检查EtherLab内核模块加载状态
执行lsmod | grep ec_master确认内核模块是否正常加载,若未加载,手动加载模块:modprobe ec_master;检查模块加载参数是否正确,可通过cat /sys/module/ec_master/parameters/*查看参数配置,重点确认是否启用了RTDM(对应代码中的USE_RTDM宏)。验证EtherCAT主站设备文件权限
确认/dev/EtherCAT0(或对应设备文件)的权限,执行ls -l /dev/EtherCAT*,确保运行程序的用户有读写权限,若权限不足,执行chmod 666 /dev/EtherCAT0或添加用户到对应设备组。排查Xenomai实时环境配置
执行xeno-test验证Xenomai核心服务是否正常运行,若测试失败,重新检查Xenomai与RT内核的编译适配性;确认程序是否正确链接Xenomai库,编译时需添加-lxenomai -lnative等链接参数,且运行时环境变量LD_LIBRARY_PATH包含Xenomai库路径。检查EtherLab内核模块与用户态库版本匹配
内核模块和用户态库版本必须完全一致,执行ecrt_version查看用户态版本,dmesg | grep ec_master查看内核模块版本,若版本不匹配,重新编译安装整套EtherLab环境。调试内核态调用阻塞原因
若以上步骤无效,启用内核调试:执行echo 1 > /proc/sys/kernel/printk打开内核日志输出,重新运行程序后通过dmesg -w实时查看内核日志,定位内核态中阻塞的具体位置;若内核日志显示卡在硬件初始化,检查EtherCAT网卡的驱动适配,确认网卡支持实时传输,且已禁用网卡的节能、中断合并等功能。验证PDO配置的一致性
虽然扫描从站正常,但需确认所有从站的PDO配置与原系统完全一致,执行ecrt_slave_config_pdos后,可通过EtherLab工具ecmastercfg查看从站状态,检查PDO映射是否正确。
内容的提问来源于stack exchange,提问作者han

