Ethercat学习-电机调试问题总结


主站硬件:STM32F405+LAN8720A

主站软件:SOEM

问题1:初始化不进入OP状态

现象描述:主站初始化过程中,打印信息显示状态一直在safe-op,AL-state(寄存器0x134)中的值为0,ESC中的配置信息正常打印

排查过程:如果AL-state有报错,那么应该先根据报错来进行排查。这次AL-state没有报错,正常来讲,流程正确的话应该进入OP状态的。个人理解,从safe-op到op状态,需要两个条件:1、发送状态切换请求;2、发送有效过程数据。

首先排查发送状态切换请求是否成功:通过wck的值就可以看到了。

其次排查过程数据发送:通过wireshake抓包可以看到过程数据的包,包长度正常,逻辑地址正常,内容可以忽略,因为现在还没开始填充,内容全是0。数据包有了,发送的长度也符合我们PDO所映射数据的长度,但是为什么通信不成功呢?进一步排查,FMMU映射是否正确,抓取FMMU映射的数据包,如下图所示:

在这里插入图片描述

在这里插入图片描述

物理地址0x1100是我配置的SM2的地址;物理地址0x1400是我配置的SM3的地址。按照习惯来,一般我们SM0、SM1、SM2、SM3分别对应的是邮箱输出(写)、邮箱输入(读)、过程数据输出(写)、过程数据输入(读);可是这里是SM2对应的FMMU配置的是读,SM3对应的配置是写。问题应该是出在了这里。

通过源码来分析原因:

首先我们在初始化配置的时候,会调用ecx_config_init,会默认初始化SMtype,为1,2,3,4(表示邮箱输出(写)、邮箱输入(读)、过程数据输出(写)、过程数据输入(读))

ecx_config_init()
    .....
          if (context->slavelist[slave].mbx_l>0)
         {   
            context->slavelist[slave].SMtype[0] = 1;
            context->slavelist[slave].SMtype[1] = 2;
            context->slavelist[slave].SMtype[2] = 3;
            context->slavelist[slave].SMtype[3] = 4;
            context->slavelist[slave].SM[0].StartAddr = htoes(context->slavelist[slave].mbx_wo);
            context->slavelist[slave].SM[0].SMlength = htoes(context->slavelist[slave].mbx_l);
            context->slavelist[slave].SM[0].SMflags = htoel(EC_DEFAULTMBXSM0);
            context->slavelist[slave].SM[1].StartAddr = htoes(context->slavelist[slave].mbx_ro);
            context->slavelist[slave].SM[1].SMlength = htoes(context->slavelist[slave].mbx_rl);
            context->slavelist[slave].SM[1].SMflags = htoel(EC_DEFAULTMBXSM1);
            context->slavelist[slave].mbx_proto = 
            ecx_readeeprom(context, slave, ECT_SII_MBXPROTO, EC_TIMEOUTEEP);
         } 
    .....

但是在IOmap的时候,会调用ecx_readPDOmapCA来读取电机程序里的对象字典0x1C00、0x1C12、0x1C13,注意是,是电机MCU中的对象字典,不是ESC的EEPROM中的。0x1C00保存的就是SMtype,程序会根据读取到的数据来修改我们初始化好的SMtype的值,接下来IOmap中会配置SM2、SM3、FMMU,在进行SM2和SM3配置的时候是根据EEPROM的数据信息来配置,在进行FMMU配置的时候会通过SMtype来判断SM的方向,然后根据方向来配置FMMU的方向。通过Twincat上位机,发现电机中0x1c00中的值是2,1,3,4;正好和习惯的配置相反,然而提供的ESC中的xml的配置却是和习惯的相同,这就造成了SM和FMMU配置的方向不正确。最终通过将程序改为如下解决了问题,烧录验证,可以跳转到OP状态。

/* 修改后的ecx_readPDOmapCA 函数 */
int ecx_readPDOmapCA(ecx_contextt *context, uint16 Slave, int *Osize, int *Isize)
{
   int wkc, rdl;
   int retVal = 0;
   uint8 nSM, iSM, tSM;
   int Tsize;
   uint8 SMt_bug_add;
   
   *Isize = 0;
   *Osize = 0;
   SMt_bug_add = 0;
   rdl = sizeof(ec_SMcommtypet); 
   context->SMcommtype->n = 0;
   /* read SyncManager Communication Type object count Complete Access*/
   wkc = ecx_SDOread(context, Slave, ECT_SDO_SMCOMMTYPE, 0x00, TRUE, &rdl, context->SMcommtype, EC_TIMEOUTRXM);
   /* positive result from slave ? */
   if ((wkc > 0) && (context->SMcommtype->n > 2))
   {
      /* make nSM equal to number of defined SM */
      nSM = context->SMcommtype->n - 1;
      /* limit to maximum number of SM defined, if true the slave can't be configured */
      if (nSM > EC_MAXSM)
      {
         nSM = EC_MAXSM;
         ecx_packeterror(context, Slave, 0, 0, 10); /* #SM larger than EC_MAXSM */         
      }
      /* iterate for every SM type defined */
      for (iSM = 2 ; iSM <= nSM ; iSM++)
      {
         /* 如果电机代码里1C00中的配置与电机SSC中的xml配置的不一样,以XML中为准 */
        if(context->slavelist[Slave].SMtype[iSM] != context->SMcommtype->SMtype[iSM])
            tSM = context->slavelist[Slave].SMtype[iSM];
//          tSM = context->SMcommtype->SMtype[iSM];

// start slave bug prevention code, remove if possible            
         if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave!
         {
            SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4
         }
         if(tSM)
         {
            tSM += SMt_bug_add; // only add if SMt > 0
         }
// end slave bug prevention code
         
          /* 源代码中的话,屏蔽掉这句话 */
//         context->slavelist[Slave].SMtype[iSM] = tSM;
         /* check if SM is unused -> clear enable flag */
         if (tSM == 0)
         {
            context->slavelist[Slave].SM[iSM].SMflags =
               htoel( etohl(context->slavelist[Slave].SM[iSM].SMflags) & EC_SMENABLEMASK);
         }
         if ((tSM == 3) || (tSM == 4))
         {
            /* read the assign PDO */
            Tsize = ecx_readPDOassignCA(context, Slave, ECT_SDO_PDOASSIGN + iSM );
            /* if a mapping is found */
            if (Tsize)
            {
               context->slavelist[Slave].SM[iSM].SMlength = htoes((Tsize + 7) / 8);
               if (tSM == 3)
               {
                  /* we are doing outputs */
                  *Osize += Tsize;
               }
               else
               {
                  /* we are doing inputs */
                  *Isize += Tsize;
               }
            }   
         }   
      }
   }

   /* found some I/O bits ? */
   if ((*Isize > 0) || (*Osize > 0))
   {
      retVal = 1;
   }
   return retVal;
}
int ecx_readPDOmap(ecx_contextt *context, uint16 Slave, int *Osize, int *Isize)
{
   int wkc, rdl;

   

int retVal = 0;
   uint8 nSM, iSM, tSM;
   int Tsize;
   uint8 SMt_bug_add;
   
   *Isize = 0;
   *Osize = 0;
   SMt_bug_add = 0;
   rdl = sizeof(nSM); nSM = 0;
   /* read SyncManager Communication Type object count */

   wkc = ecx_SDOread(context, Slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM);

   /* positive result from slave ? */
   if ((wkc > 0) && (nSM > 2))
   {
      /* make nSM equal to number of defined SM */
      nSM--;
      /* limit to maximum number of SM defined, if true the slave can't be configured */
      if (nSM > EC_MAXSM)
         nSM = EC_MAXSM;
      /* iterate for every SM type defined */
      for (iSM = 2 ; iSM <= nSM ; iSM++)
      {
         rdl = sizeof(tSM); tSM = 0;
         /* read SyncManager Communication Type */
         wkc = ecx_SDOread(context, Slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM);
         if (wkc > 0)
         {
           /* 如果电机代码里1C00中的配置与电机SSC中的xml配置的不一样,以XML中为准 */
          if(context->slavelist[Slave].SMtype[iSM] != tSM)
            tSM = context->slavelist[Slave].SMtype[iSM];
// start slave bug prevention code, remove if possible            
            if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave!
            {   
               SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4
            }
            if(tSM)
            {   
               tSM += SMt_bug_add; // only add if SMt > 0
            }
            if((iSM == 2) && (tSM == 0)) // SM2 has type 0, this is a bug in the slave!
            {   
               tSM = 3;
            }
            if((iSM == 3) && (tSM == 0)) // SM3 has type 0, this is a bug in the slave!
            {   
               tSM = 4;
            }
// end slave bug prevention code            
             /* 源代码中的话,屏蔽掉这句话 */
//            context->slavelist[Slave].SMtype[iSM] = tSM;
						
            /* check if SM is unused -> clear enable flag */
            if (tSM == 0)
            {
               context->slavelist[Slave].SM[iSM].SMflags = 
                  htoel( etohl(context->slavelist[Slave].SM[iSM].SMflags) & EC_SMENABLEMASK);
            }
            if ((tSM == 3) || (tSM == 4))
            {
               /* read the assign PDO */
               Tsize = ecx_readPDOassign(context, Slave, ECT_SDO_PDOASSIGN + iSM );
               /* if a mapping is found */
               if (Tsize)
               {
                  context->slavelist[Slave].SM[iSM].SMlength = htoes((Tsize + 7) / 8);
                  if (tSM == 3)
                  {  
                     /* we are doing outputs */
                     *Osize += Tsize;
                  }
                  else
                  {
                     /* we are doing inputs */
                     *Isize += Tsize;
                  }   
               }   
            }   
         }   
      }
   }

   /* found some I/O bits ? */
   if ((*Isize > 0) || (*Osize > 0))
   {
      retVal = 1;
   }
      
   return retVal;
}

除此之外,ecx_config_init函数中也做了一点改动,这里主要是将EEPROM中读取到的值给到SMtype,之前是用的默认的值

         /**************  ecx_config_init *************/
          /* SII SM section */
            nSM = ecx_siiSM(context, slave, context->eepSM);
            if (nSM>0)
            {   
               context->slavelist[slave].SM[0].StartAddr = htoes(context->eepSM->PhStart);
               context->slavelist[slave].SM[0].SMlength = htoes(context->eepSM->Plength);
               context->slavelist[slave].SM[0].SMflags = 
                  htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16));
               
               /*****读取EEPROM内存中的SM类型 */
               context->slavelist[slave].SMtype[0] = context->eepSM->PDIctrl;
               /*************/

               SMc = 1;
               while ((SMc < EC_MAXSM) &&  ecx_siiSMnext(context, slave, context->eepSM, SMc))
               {
                  context->slavelist[slave].SM[SMc].StartAddr = htoes(context->eepSM->PhStart);
                  context->slavelist[slave].SM[SMc].SMlength = htoes(context->eepSM->Plength);
                  context->slavelist[slave].SM[SMc].SMflags = 
                     htoel((context->eepSM->Creg) + (context->eepSM->Activate << 16));
                  /*****读取EEPROM内存中的SM类型 */
                  context->slavelist[slave].SMtype[SMc] = context->eepSM->PDIctrl;
                  /*************/
                  SMc++;

               }   
            } 
问题2:PDO通讯数据不对

测试与电机通讯,发现对象字典写不进去,例如工作模式6060、6040。仔细检查PDO配置的代码,代码没问题。链接TWinCAT,可以看到1600的部分的内容确实是我程序里写的内容。但是1C12中的内容却是1700。在主站初始化的时候去读取1C12中的数据来计算IOmap的输出数据长度。debug的时候看到读取到的1C12的数据也1600,映射长度也是程序里设置的长度。说明当时确实是将1600成功写入了1C12。但是现在TWinCAT中看到的是1700,说明数据后来又被改回来了 ,至于是SOEM改的还是电机自己改的,还不太清楚。尝试将程序里的1600也改为1700,问题解决。另外关于PDO的映射有时候映射的数据需要补位一个无意义的映射,目前还不清楚这个补位的原则和道理。

0的部分的内容确实是我程序里写的内容。但是1C12中的内容却是1700。在主站初始化的时候去读取1C12中的数据来计算IOmap的输出数据长度。debug的时候看到读取到的1C12的数据也1600,映射长度也是程序里设置的长度。说明当时确实是将1600成功写入了1C12。但是现在TWinCaT中看到的是1700,说明数据后来又被改回来了 ,至于是SOEM改的还是电机自己改的,还不太清楚。尝试将程序里的1600也改为1700,问题解决。另外关于PDO的映射有时候映射的数据需要补位一个无意义的映射,目前还不清楚这个补位的原则和道理。

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值