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

news2024/11/24 22:55:26

文章目录

        • 问题1:初始化不进入OP状态
        • 问题2:PDO通讯数据不对

主站硬件:STM32F405+LAN8720A

主站软件:SOEM

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

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

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

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

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

在这里插入图片描述

在这里插入图片描述

物理地址0x1100是我配置的SM2的地址;物理地址0x1100是我配置的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中的对象字典,不是SSC,EPROM的。0x1C00保存的就是SMtype,程序会根据读取到的数据来修改我们初始化好的SMtype的值,接下来IOmap中会配置SM2、SM3、FMMU,在进行SM2和SM3配置的时候是根据EEPROM的数据信息来配置,在进行FMMU配置的时候会通过SMtype来判断SM的方向,然后根据方向来配置FMMU的方向。通过Twincat上位机,发现电机中0x1c00中的值是2,1,3,4;正好和习惯的配置相反,然而提供的SSC中的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的映射有时候映射的数据需要补位一个无意义的映射,目前还不清楚这个补位的原则和道理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/403613.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多态且原理

多态 文章目录多态多态的定义和条件协变&#xff08;父类和子类的返回值类型不同&#xff09;函数隐藏和虚函数重写的比较析构函数的重写关键字final和override抽象类多态的原理单继承和多继承的虚函数表单继承下的虚函数表多继承下的虚函数表多态的定义和条件 定义&#xff1…

Python批量爬取游戏卡牌信息

文章目录前言一、需求二、分析三、处理四、运行结果前言 本系列文章来源于真实的需求本系列文章你来提我来做本系列文章仅供学习参考阅读人群&#xff1a;有Python基础、Scrapy框架基础 一、需求 全站爬取游戏卡牌信息 二、分析 查看网页源代码&#xff0c;图片资源是否存在…

Node.js + MongoDB 搭建博客 -- 登录页面

准备工作 安装Node.js安装express等相关库MongoDB数据库电脑系统&#xff1a;win11 功能分析 搭建一个简单的具有多人注册、登录、发表文章以及登出功能的博客。 设计目标 未登录&#xff1a;主页左侧导航栏显示home、login、register&#xff0c;右侧显示已发表的文章、发…

视觉SLAM14讲第三章习题作业

这是本人的解答&#xff0c;并非官方解答 验证旋转矩阵是正交矩阵 在第44页中&#xff0c;旋转矩阵的引入是这样的&#xff1a; 所以&#xff0c;我们需要验证矩阵 R[e1Te1′e1Te2′e1Te3′e2Te1′e2Te2′e2Te3′e3Te1′e3Te2′e3Te3′]R \begin{bmatrix} e_1^{T}e_1^{}&am…

【Java开发】设计模式 02:工厂模式

1 工厂模式介绍工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使…

Weblogic管理控制台未授权远程命令执行漏洞复现(cve-2020-14882/cve-2020-14883)

目录漏洞描述影响版本漏洞复现权限绕过漏洞远程命令执行声明&#xff1a;本文仅供学习参考&#xff0c;其中涉及的一切资源均来源于网络&#xff0c;请勿用于任何非法行为&#xff0c;否则您将自行承担相应后果&#xff0c;本人不承担任何法律及连带责任。 漏洞描述 Weblogic…

CorelDRAW2023最新版新增功能200多个新模板

CorelDRAW是一款平面矢量绘图排版软件&#xff0c;CorelDRAW运用涵盖企业VI设计&#xff0c;广告设计&#xff0c;包装设计&#xff0c;画册设计&#xff0c;海报、招贴设计&#xff0c;UI界面设计&#xff0c;网页设计&#xff0c;书籍装帧设计&#xff0c;插画设计&#xff0…

韩信点兵问题,鸡兔同笼问题,闰年判断问题等,我用Python瞬间搞定(13)

小朋友们好&#xff0c;大朋友们好&#xff01;我是猫妹&#xff0c;一名爱上Python编程的小学生。欢迎和猫妹一起&#xff0c;趣味学Python。今日主题最近猫妹一直在练习Python编程&#xff0c;有些习题真是经典啊&#xff01;比如韩信点兵问题&#xff0c;比如鸡兔同笼问题等…

【Linux】线程实例 | 简单线程池

今天来写一个简单版本的线程池 1.啥是线程池 池塘&#xff0c;顾名思义&#xff0c;线程池就是一个有很多线程的容器。 我们只需要把任务交到这个线程的池子里面&#xff0c;其就能帮我们多线程执行任务&#xff0c;计算出结果。 与阻塞队列不同的是&#xff0c;线程池中内有…

代码随想录刷题-数组-螺旋矩阵II

文章目录螺旋矩阵 II习题我的解法别人的解法螺旋矩阵 II 本节对应代码随想录中&#xff1a;代码随想录&#xff0c;讲解视频&#xff1a;一入循环深似海 | LeetCode&#xff1a;59.螺旋矩阵II_哔哩哔哩_bilibili 习题 题目链接&#xff1a;59. 螺旋矩阵 II - 力扣&#xff0…

将spring boot项目打包成一个可执行的jar包

将spring boot项目打包成一个可执行的jar包&#xff0c;jar包自带了整个运行环境简化配置&#xff0c;可直接运行&#xff0c;本次使用HelloWorld项目演示。 创建Spring Boot项目在pom.xml中导入插件 <build><plugins><plugin><groupId>org.springfr…

计算机网络:移动IP

移动IP相关概念 移动IP技术是移动结点&#xff08;计算机/服务器&#xff09;以固体的网络IP地址&#xff0c;实现跨越不同网段的漫游功能&#xff0c;并保证了基于网络IP的网络权限在漫游中不发生任何改变。移动结点&#xff1a;具有永久IP地址的设备。归属代理&#xff08;本…

西瓜播放器全屏功能源码分析

H5业务中使用了西瓜播放器&#xff0c;嵌入各个APP&#xff0c;全屏时候会有相应的差异。带着好奇心&#xff0c;阅读一下xgpplayer全屏功能部分源代码。源码地址一、工具方法其他方法看名称就知道是dom操作相关&#xff0c;无需多说&#xff0c;上面这两个工具方法主要用来检测…

数学建模资料整理

数学建模中有三类团队&#xff1a; 第一类&#xff1a;拿到题目&#xff0c;讨论&#xff0c;然后建模手开始建模&#xff0c;编程手开始处理数据&#xff0c;写作手开始写作。 第二类&#xff1a;拿到题目&#xff0c;团内大佬&#xff0c;开始建模&#xff0c;然后编程&#…

【GAOPS055】verilog 乘法、除法和取余

乘法硬件原理结论思路1思路2举例编码仿真综合除法硬件原理verilog代码仿真结果资源占用乘法硬件原理 结论 可以将乘法A x B转为A的移位相加。 利用乘2n就是左移n位的特性乘2^n就是左移n位的特性乘2n就是左移n位的特性&#xff0c;将数拆分为2n2^n2n表示 思路1 原始列竖式计…

【C++】通过priority_queue、reverse_iterator加深对于适配器和仿函数的理解

苦尽甘来 文章目录一、仿函数&#xff08;仿函数就是一个封装()运算符重载的类&#xff09;1.C语言的函数指针2.C的仿函数对象二、priority_queue中的仿函数1.模拟实现优先级队列1.1 优先级队列的本质&#xff08;底层容器为vector的适配器&#xff09;1.2 向下调整算法建堆1.3…

git添加子模块(submodule)

git添加子模块(submodule) 背景 有时候自己的项目需要用到别人的开源代码&#xff0c;例如 freertos 和 tinyusb 这个时候有两种选择 将开源的代码下载下来放到自己的 git 中管理 缺点&#xff1a;如果远端仓库更新&#xff0c;自己仓库的代码不会更新 将开源代码通过子模块…

2023河北沃克HEGERLS甘肃金昌重型仓储项目案例|托盘式四向穿梭车智能密集存储系统在工业行业的创新应用

项目名称&#xff1a;自动化仓储托盘式四向穿梭车智能密集立体库项目 项目合作客户&#xff1a;甘肃省金昌市某集团企业 项目施工地域&#xff1a;甘肃省金昌市 设计与承建单位&#xff1a;河北沃克金属制品有限公司&#xff08;自主品牌&#xff1a;海格里斯HEGERLS&#x…

Mysql的Explain关键字

引入 MySQL为我们提供了 explain 关键字来直观的查看一条SQL的执行计划 概念 1.id SELECT识别符&#xff0c;这是SELECT的查询序列号 2.select_type 查询类型 SIMPLE:简单SELECT(不使用UNION或子查询) PRIMARY:最外面的SELECT UNION:UNION中的第二个或后面的SELECT语句 DEPEND…

你的游戏帐号是如何被盗的

据报道&#xff0c;2022上半年&#xff0c;中国游戏市场用户规模达到了5.54亿人&#xff0c;游戏市场销售收入1163.1亿元&#xff0c;相较去年均为同比增长的情况。如此庞大的市场规模&#xff0c;黑色产业链是绕不开的话题。 但相较于游戏中大家常见的玩家与玩家、玩家与官方…