1. 代码编写
根据图2的信息,我们可以看出输出有三个变量,DI_1,AI_1,AI_2,长度分别为8位,8位,16位,输入有三个变量DO_1,AO_1,AO_2,长度分别位8位,8位,16位,定义结构体:
//过程数据,写入从站的数据格式
typedef struct{
uint8_t DI_1;
uint8_t AI_1;
uint16_t AI_2;
}PDO_OUTPUTS_T;
//过程数据,从站返回的数据格式
typedef struct{
uint8_t DO_1;
uint8_t AO_1;
uint16_t AO_2;
}PDO_INPUTS_T;
第一步,输入需要控制的pcie卡别名以及通道号,获取Ecat控制句柄。
EXIT_IF_FAIL(EcatOpen(&hHandle, BOARD_ALIAS(buff, alias), channel));
EXIT_IF_FAIL(EcatBusRun(hHandle, fileName));
EXIT_IF_FAIL(EcatRequestMasterState(hHandle, EcatStateO));
uint8_t query = EcatStateNotSet;
do{
EXIT_IF_FAIL(EcatGetMasterState(hHandle, &query));
//输出当前状态
_DBG_("request_state=%d, query_state=%d", EcatStateO, query);
if (query == EcatStateO){
break;;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}while(1);
第四步,定义PDO过程数据的指针并指向本地缓存空间,这一步将会让我们更加方便快捷地读写PDO数据。
PDO_OUTPUTS_T *outputBuff;
PDO_INPUTS_T *inputBuff;
//将指针inputBuff,outputBuff分别指向本地缓存的空间
EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_INPUT, (void**)&inputBuff));
EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_OUTPUT, (void**)&outputBuff));
for(auto i = 0; i < 2; i++){
EcatPIOutputQueuePush(hHandle, false, 100);
}
EXIT_IF_FAIL(EcatPIEnable(hHandle));
bool loopFlag = true;
while(loopFlag){
//阻塞式等待PDO数据
if (!EcatPIInputQueuePop(hHandle, false, 100)){
/*********************************************************/
//修改过程数据
printf("0x%02x, 0x%02x, 0x%04x\r\n", inputBuff->DO_1, inputBuff->AO_1, inputBuff->AO_2);
outputBuff->DI_1 = inputBuff->DO_1;
outputBuff->AI_1 = inputBuff->AO_1;
outputBuff->AI_2 = inputBuff->AO_2;
/*********************************************************/
//将数据添加到PDO的发送队列中
if (EcatPIOutputQueuePush(hHandle, false, 100)){
_ERR_("PI push error.");
break;
}
}
}
EXIT_IF_FAIL(EcatClose(hHandle));
//过程数据,写入从站的数据格式
typedef struct{
uint8_t DI_1;
uint8_t AI_1;
uint16_t AI_2;
}PDO_OUTPUTS_T;
//过程数据,从站返回的数据格式
typedef struct{
uint8_t DO_1;
uint8_t AO_1;
uint16_t AO_2
}PDO_INPUTS_T;
int32_t testDemo(int alias, int channel, const char* fileName){
int32_t result = 0;
char buff[256];
ECAT_HANDLE hHandle;
//初始化hHandle句柄
EXIT_IF_FAIL(EcatOpen(&hHandle, BOARD_ALIAS(buff, alias), channel));
//启动主站
EXIT_IF_FAIL(EcatBusRun(hHandle, fileName));
//将状态切换为8(Operational)
EXIT_IF_FAIL(EcatRequestMasterState(hHandle, EcatStateO));
//等待主站切换状态
uint8_t query = EcatStateNotSet;
do{
EXIT_IF_FAIL(EcatGetMasterState(hHandle, &query));
//输出当前状态
_DBG_("request_state=%d, query_state=%d", EcatStateO, query);
if (query == EcatStateO){
break;;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}while(1);
PDO_OUTPUTS_T *outputBuff;
PDO_INPUTS_T *inputBuff;
//将指针inputBuff,outputBuff分别指向本地缓存的空间
EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_INPUT, (void**)&inputBuff));
EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_OUTPUT, (void**)&outputBuff));
//向发送队列中添加空数据,添加空数据的数量取决于PC系统抖动的程度,抖动越小,添加的空数据越少,控制指令的滞后性越小
for(auto i = 0; i < 2; i++){
EcatPIOutputQueuePush(hHandle, false, 100);
}
//使能过程数据PDO通信
EXIT_IF_FAIL(EcatPIEnable(hHandle));
bool loopFlag = true;
while(loopFlag){
//阻塞式等待PDO数据
if (!EcatPIInputQueuePop(hHandle, false, 100)){
/*********************************************************/
//修改过程数据
printf("0x%02x, 0x%02x, 0x%04x\r\n", inputBuff->DO_1,inputBuff->AO_1, inputBuff->AO_2);
outputBuff->DI_1 = inputBuff->DO_1;
outputBuff->AI_1 = inputBuff->AO_1;
outputBuff->AI_2 = inputBuff->AO_2;
/*********************************************************/
//将数据添加到PDO的发送队列中
if (EcatPIOutputQueuePush(hHandle, false, 100)){
_ERR_("PI push error.");
break;
}
}
}
//释放句柄
EXIT_IF_FAIL(EcatClose(hHandle));
return result;
}
int main(int argc, char* argv[]){
ECAT_HANDLE hHandle;
char buff[256];
uint32_t channel = 0, alias = 0;
std::string eniFile;
if (argc != 4){
std::cout << "usage: " << argv[0] << " encoder_id channel eni.xml" << std::endl;
return 1;
}
alias = atoi(argv[1]);
channel = atoi(argv[2]);
eniFile = argv[3];
if (channel > 1){
channel = 1;
}
testDemo(alias, channel, eniFile.c_str());
return 0;
}
但真正开发的时候,建议将打印信息等耗时的操作注释后再编译,否则,程序将可能会因为打印动作耗时过长而导致主机无法快速填充pdo数据,最终将产生控制抖动等问题。
EtherCAT 系列文章
【新品上市】ZMC900E 国产高性能EtherCAT总线控制器
【新品上市】ZLG致远电子PCIe EtherCAT通讯卡产品正式发布!
【200个电机驱动】如何实现EtherCAT分布式供电?
【200个电机驱动】如何同步运行?--基于EtherCAT的柔性电机驱动系统
【200个电机驱动】如何快速搭建柔性自动生产线?
【插针机PLC开发】用AWBlock开发运动逻辑
【插针机HMI开发】用AWTK开发人机界面
【技术分享】EtherCAT 数据帧格式和寻址方式简介
【技术分享】“脱胎换骨”--插针机运动控制
【技术分享】EtherCAT总线如何对从站固件进行升级?
【技术分享】EtherCAT冗余技术如何实现通信线缆断开的补救?
【技术分享】如何精准分析人形机器人运动数据?
【技术分享】为何EtherCAT在运动控制总线中如此受欢迎?
【产品应用】使用PCIe EtherCAT通讯卡控制IO从站step by step(一)
【产品应用】ZMC900E控制器之ROS2环境安装指南
【产品应用】EtherCAT主站控制器系统实时性测试
【产品应用】ZMC900E 国产EtherCAT主站控制器 — 电源口传导骚扰整改
【产品应用】ZMC300E EtherCAT主站控制器实现复杂的运动轨迹规划原理及应用
【产品应用】手把手带你使用ZMC300E绘图
【产品应用】三个步骤,让你的EtherCAT电机转起来
【产品应用】EtherCAT如何保障高效率、高实时性、高灵活性的现场总线通讯
【产品介绍】ZMC601E总线型边缘控制器 — 引领制造型企业数字化转型
【产品介绍】ZMC600E EtherCAT主站控制器全新上市
【产品介绍】ZLG推出新一代工业机器人解决方案,为工业机器人注入新的活力
更多往期文章,请点击“ 阅读原文 ”。