我们的套件在使用 EtherCAT 控制电机时,采用了 CANopen 应用层协议中的 CiA402 规范。为了更好地理解 CiA402 的工作原理,我们先简要回顾一下 CANopen 协议。CANopen 是一个基于 CAN 协议的通信协议,广泛应用于工业自动化领域。PDO(过程数据对象)和 SDO(服务数据对象)是 CANopen 协议中的核心概念,用于在网络节点之间传输数据和提供服务。
在 CANopen 协议中,每个节点都维护一个称为对象字典(Object Dictionary,OD)的数据结构。对象字典是节点信息的中央仓库,包含了节点的配置信息、通信参数以及过程数据(PDO)等。上层应用通过与对象字典的交互来实现通信和控制。PDO 特别适合快速的数据处理与传输,因为它们被设计为直接映射到 CAN 帧,从而减少了处理时间和网络延迟。
在对象字典中,PDO 是由多个条目(Entry)构成的,每个条目都通过特定的索引(Index)、子索引(Subindex)和位数(Bit Length)来定义其数据源和属性。这种结构化的组织方式使得 PDO 的配置和管理变得简单而高效。
现在,我们回到 EtherCAT 和 CoE(CAN over EtherCAT)的话题。EtherCAT 是一种高性能的工业以太网协议,用于实时数据交换和分布式控制。CoE 是 EtherCAT 中用于支持 CANopen 协议的一个子协议,它允许 EtherCAT 网络中的节点使用 CANopen 的对象字典和通信机制。
在套件实现中,我们可以看到对 CiA402 的支持。CiA402 是一个针对驱动器和运动控制器的 CANopen 应用层规范。在源代码中,如 CiA402appl.c 文件中的 UINT16 CiA402_Init(void) 函数,就包含了与 CiA402 相关的初始化代码。这部分代码负责设置和配置与 CiA402 相关的对象字典条目、PDO 映射等,以支持特定的电机控制功能。
通过深入分析这些代码,我们可以更深入地理解 CiA402 在 EtherCAT 控制系统中的应用和实现方式。
CiA402_Init(void) 函数如下所示:
//声明并初始化对象字典
LocalAxes[AxisCnt].ObjDic = (TOBJECT *) LLOCMEM(SIZEOF(DefCiA402AxisObjDic));
HMEMCPY(LocalAxes[AxisCnt].ObjDic,&DefCiA402AxisObjDic,SIZEOF(DefCiA402AxisObjDic));
{
TOBJECT OBJMEM *pDiCEntry = LocalAxes[AxisCnt].ObjDic;
/*初始化每一个条目,表示其指向哪一个变量*/
while(pDiCEntry->Index != 0xFFFF)
{
BOOL bObjectFound = TRUE;
switch(pDiCEntry->Index)
{
case 0x1600://PDO映射方式1(CSV/CSP)
pDiCEntry->pVarPtr = &LocalAxes[AxisCnt].Objects.sRxPDOMap0;
break;
case 0x1601://PDO映射方式2(CSP)
pDiCEntry->pVarPtr = &LocalAxes[AxisCnt].Objects.sRxPDOMap1;
break;
case 0x1602://PDO映射方式3(CSV)
pDiCEntry->pVarPtr = &LocalAxes[AxisCnt].Objects.sRxPDOMap2;
break;
... ... ...
case 0x6064:
pDiCEntry->pVarPtr = &LocalAxes[AxisCnt].Objects.objPositionActualValue;
break;
... ... ...
default :
bObjectFound = FALSE;
break;
}
可以看到这段代码初始化了几个对象字典(AxisCnt),每个电机轴都对应一个对象字典(Object Dictionary),用于存储和管理该轴的状态、参数和实时数据。这些对象字典条目通过特定的索引和子索引进行唯一标识,并被初始化以指向实际的变量或数据结构。并且对对象字典中每一个条目进行了初始化,使其指向一个实际的变量。目前例程中并不是所有条目都有用到,我们看一个实际用到的条目:
case 0x6064:
pDiCEntry->pVarPtr = &LocalAxes[AxisCnt].Objects.objPositionActualValue;
break;
索引0x6064的条目通常用于存储电机的实际位置值。在初始化过程中,该条目会被关联到LocalAxes[AxisCnt].Objects.objPositionActualValue这个变量上,从而实现了实际变量与对象字典条目的关联。
为了通过网络传输这些变量,我们需要用到PDO,为了实现PDO传输,我们需要将PDO与对象字典条目进行关联或映射。
在对象字典的前几个条目中,0x1600、0x1601、0x1602等通常用于定义RxPDO(接收过程数据对象)的映射方式,而0x1A00、0x1A01、0x1A02等则用于定义TxPDO(发送过程数据对象)的映射方式。这些映射方式对应于电机的不同工作模式,如CSV/CSP、CSV和CSP等。需要注意的是,这三种映射方式中,通常只有一种会被激活使用,以适应当前的工作模式。
在CiA402_Init(void)函数的开始部分,通过以下代码:
HMEMCPY(&LocalAxes[AxisCnt].Objects,&DefCiA402ObjectValues,CIA402_OBJECTS_SIZE);
每个电机轴的对象字典和PDO映射都会被初始化为预定义的默认值,这些默认值存储在DefCiA402ObjectValues这个变量中。以case 0x1601为例,其具体内容为:{3, {0x60400010,0x607A0020,0x00000010 }}, /*TOBJ1601*/
这里,3表示PDO映射包含三个条目。接下来的三个对(索引和大小)定义了PDO中应包含的数据:
- 0x6040 和 0x0010 表示从对象字典索引0x6040开始,传输16位(0x10)的数据。
- 0x607A 和 0x0020 表示从对象字典索引0x607A开始,传输32位(0x20)的数据。
- 最后一个对用于填充对齐。
表示0x1601这种映射方式下RxPDO映射到0x6064以及0x607A条目的内容。
另外我们再关注一下UINT16 CiA402_Init(void)函数中下面这段代码
/*increment object index*/
if (pDiCEntry->Index >= 0x1400 && pDiCEntry->Index <= 0x1BFF) //PDO region
{
pDiCEntry->Index += AxisCnt* PDOOffset;
}
else
{
pDiCEntry->Index += AxisCnt* (UINT16)ObjectOffset;
}
因为我们知道这个从站可以同时控制最多四个电机,因此不同电机之间对象字典索引是不能一样的,这段代码就是使得每个电机的对象字典索引有一个偏移量从而进行区分。
通过以上代码我们可以确定从站设备的配置中,存在三种PDO(过程数据对象)映射方式,这些映射方式对应于不同的操作模式或数据传输需求。然而,在任何给定的时间,从站只会使用其中的一种映射方式来传输数据。
ApplicationObjDic字典是一个包含应用层相关参数的对象字典。在这个字典中,条目0x1C12和0x1C13(或类似的索引)通常用于存储RxPDO(接收PDO)和TxPDO(发送PDO)的映射配置信息。这两个变量,即sRxPDOassign和sTxPDOassign,定义了从站应该接收和发送哪些数据,以及这些数据在PDO中的布局。
我们再看一下函数void APPL_OutputMapping(UINT16* pData)和void APPL_InputMapping(UINT16* pData),这两个函数用于处理PDO数据的映射。在这些函数中,switch语句用于根据sTxPDOassign.aEntries[j]或sRxPDOassign.aEntries[j]的某个部分(通常是低四位,通过& 0x000F得到)来决定当前处理的是哪种PDO映射。
通过修改ApplicationObjDic字典中的0x1C12和0x1C13条目(即sRxPDOassign和sTxPDOassign变量),开发人员可以动态地调整RxPDO和TxPDO的数据内容。这允许在运行时更改数据传输的格式和类型,以适应不同的操作模式或应用需求。
在TwinCAT主站软件中,这些修改通常是在工程文件的相应配置页面(如Slots标签页)中进行的(目前从站只支持CSP模式)。
我们看一下下图标签页Startup里面的内容也会随之改变。
其中前两条刚好是修改0x1C12和0x1C13的内容,完成这些修改后,相关的配置变化会在从站状态机从Pre-Operational(预操作)状态转换到Safe-Operational(安全操作)状态时生效。这个通信过程通常是通过EtherCAT邮箱机制(SDO,服务数据对象)进行的。
具体到从站代码层面,当主站通过SDO邮箱机制发送新的PDO映射配置时,从站会接收到这些配置数据,并在UINT8 SDOS_SdoInd(TINITSDOMBX MBXMEM *pSdoInd)这样的函数中处理这些数据。这个函数负责解析主站发送的SDO请求,并根据请求的内容更新从站内部的对象字典(如0x1C12和0x1C13条目),从而修改RxPDO和TxPDO的映射配置。
一旦这些配置更新完成,从站的过程数据(PDOs)就会根据新的映射配置进行传输,从而可能改变从站的工作模式或数据传输格式。这个过程允许开发者在运行时动态地调整从站的行为,以适应不同的应用需求或操作场景。
总结来说,通过TwinCAT主站软件修改PDO映射配置,并利用EtherCAT的SDO邮箱机制将这些配置下发到从站,可以实现从站过程数据的动态修改和工作模式的灵活调整。
到这里,对象字典初始化以及配置都完成,主站就可以通过过程数据对从站进行控制了
。我们以一个电机为例,在TwinCAT中可以看到实际使用的过程数据,如下图所示:
0x6041表示Status Word,0x6064表示ActualPosition,这两个数据传输方向为从机到主站,0x6040表示Control Word,0x607A表示TargetPosition,这两个数据传输方向为主站到从站。
主站与从站的通信接口已经配置完成了,为了实现CiA 402规范定义的电机控制,从站必须运行一个状态机来管理其操作状态和响应主站的控制命令。这个状态机定义了从站在不同阶段的操作能力和状态,以便主站可以根据这些状态来发送适当的控制命令。从站主要通过函数CiA402_StateMachine()实现CiA402的状态转换,包含以下几个状态:
#define STATE_NOT_READY_TO_SWITCH_ON 0x0001 /**< brief Not ready to switch on (optional)*/
#define STATE_SWITCH_ON_DISABLED 0x0002 /**< brief Switch on but disabled (optional)*/
#define STATE_READY_TO_SWITCH_ON 0x0004 /**< brief Ready to switch on (mandatory)*/
#define STATE_SWITCHED_ON 0x0008 /**< brief Switch on (mandatory)*/
#define STATE_OPERATION_ENABLED 0x0010 /**< brief Operation enabled (mandatory)*/
#define STATE_QUICK_STOP_ACTIVE 0x0020 /**< brief Quick stop active (optional)*/
#define STATE_FAULT_REACTION_ACTIVE 0x0040 /**< brief Fault reaction active (mandatory)*/
#define STATE_FAULT 0x0080 /**< brief Fault state (mandatory)*/
与此同时,主机通过读取从机的Status Word(索引0x6041)来了解从机的当前状态。尽管Status Word的某些位可能与状态机的状态相对应,但两者并不完全相同。Status Word提供了关于从机当前状态和可能发生的故障或警告的详细信息。,Status Word各bit含义如下:
主机通过Control Word(索引0x6040)向从机发送控制命令,以改变其操作状态或触发特定的动作。Control Word的各个位定义了不同的控制命令。控制字Control Word 各bit含义如下:
在IGH主站控制从站CiA 402状态机的一个例程中,函数axis_start根据从机的当前状态(通过status参数传入)和所需的工作模式(mode参数)来决定发送何种Control Word:
static int axis_start(nser_axle *ns_axis, uint16_t status, uint8_t mode) {
int ret = 0;
axle_state s = get_axle_state(status);
if (status & 0x8) {
nser_pdo_set_Controlword(ns_axis, 0x80);
return 0;
}
switch (s) {
case (no_ready_to_switch_on):
case (switch_on_disable):
nser_pdo_set_Controlword(ns_axis, contrlword_shutdown(0));
break;
case (ready_to_switch_on):
nser_pdo_set_Controlword(ns_axis, contrlword_switch_on(0));
break;
case (switched_on):
nser_pdo_set_Controlword(ns_axis, contrlword_enable_operation(0));
nser_pdo_set_Modes_of_operation(ns_axis, mode);
break;
case (operation_enable):
ret = 1;
break;
case (quick_stop_active):
case (fault_reaction_active):
case (fault):
default:
ret = -1;
}
return ret;
}
在CiA 402协议中,当从站成功达到STATE_OPERATION_ENABLED状态后,这标志着从站已准备好接收并执行来自主站的控制命令。此时,主站可以开始通过发送TargetPosition(索引0x607A)来指定从站电机的目标位置,并可以通过读取ActualPosition(索引0x6064)来监控电机的实时位置。