Power PMAC运动控制器 —— 学习笔记1

    有很多朋友跟博主一样,拿到PMAC控制器后一脸懵逼,技术只给了几个英文手册,便什么都不管了,咨询问题的时候敷衍了事。为了避免更多朋友像博主一样,决定跟大家分享一下Power PMAC运动控制器的使用经验。


    项目结题,分析原因,我发现我们刚拿到控制器时迷茫的原因有三:

  • 其一,没有任何经验,害怕设备损害的害怕心理;
  • 其二,没有人领进门,即使刚开始的时候技术给提供帮助,在一无所知、大脑一片空白的情况下很快就会忘记技术所给你讲过的内容;
  • 其三,手册的内容太多,且为英文,而多数人英语阅读能力有限

        但是,当你了解到整个开发过程后,再回过头来看,发现手册还是最好的老师

                                                    于2019.08.10修


为了方便大家检索,下面列出学习笔记的目录。

关于 《Power PMAC运动控制器 —— 学习笔记》 系列,目录如下:

  1. Power PMAC运动控制器——学习笔记1,主要介绍了PMAC与IDE环境的连接以及项目的创建
  2. Power PMAC运动控制器——学习笔记2,主要介绍了电机、EtherCAT网络在IDE中的配置以及基本的运动程序编写知识基础
  3. Power PMAC运动控制器——学习笔记3,主要介绍了PMAC中关于座标系、轴和运动模式的概念,以及运动程序的编写
  4. Power PMAC运动控制器——学习笔记4,主要介绍了正逆运动学在PMAC中的实现
  5. Power PMAC运动控制器——学习笔记5,主要介绍了PLC程序和子程序的编写
  6. Power PMAC运动控制器——学习笔记6,主要介绍了Power PMAC中Modbus通信的实现以及EtherCAT网络的使能
    7. Power PMAC运动控制器——学习笔记7,主要介绍了Power PMAC在机械臂控制上的应用案例

说明

       博主由于项目需要开始接触PMAC系列运动控制卡 ,奈何资料太少,能找到的资料由于版本不同的原因导致无法使用,本着开源精神,以此记录整个项目过程中Power PMAC的使用,希望能同各路大神交流分享~

目标:上位机通过Modbus TCP给运动控制卡发送指令实现机械臂的同步控制

1. 硬件介绍

       PMAC全称Programmable Multi-Axis Controller(可编程多轴运动控制器 ),是美国Delta Tau Data System 公司(现已被欧姆龙收购,说到被收购我就不得不吐槽一下,自从被收购以后技术大牛都走了,遇到技术问题只能用户自己瞎摸索,欧姆龙你上点心好嘛 😂 )推出的运动控制器[^1],功能很强大,号称可实现纳米级控制,同步性不错,尤其是插补功能做的非常好,并且支持多厂商的驱动器、光栅尺等。
       本文主要介绍项目中用到的欧姆龙的CK3M型号,模块化的设计深得我心,可实现单元的扩展,而且单元之间的连接无需工具。规格参数如下图所示:


性能参数

       系统基本构成如下图所示:

       更多细节就不多介绍了,详情请参考官网

2. 准备工作

       首先安装PowerPMAC IDE,该IDE环境是基于VS2015开发的,如果你熟悉VS工作环境,那么必然非常容易上手该IDE(如图所示)。


如果你不清楚环境的使用,可以在工具栏的帮助目录下找到PowerPMAC IDE手册,如下所示:

       在熟悉了IDE环境之后(相当于废话哈哈哈哈,直接上手即可),我们直接开干~
需要的手册主要有:软件参考手册、用户使用手册,所有文件已在百度云盘共享(失效请留言)。

3. PMAC与上位机的连接

  • step1 用双绞线电缆建立CK3M与电脑主机的连接,然后给CK3M上电(注意:千万千万千万别接反了,不然稍不留神上万元就没了 😂 )。
  • step2 PMAC默认IP为192.168.0.200,握手成功后我们打开IDE环境,点击:通讯设置->应用,注意要选择设备的IP地址。

    在这里插入图片描述

①连接成功后,IDE的标题栏会显示PMAC的版本信息,且由灰色变为绿色。

在这里插入图片描述

②如果连接失败或者连接没反应,我们可以通过<运行>功能ping一下PMAC,查看是否已经握手成功,如果已经握手成功(如下图所示),上位机会收到CK3M的反馈。
运行:window + R


在这里插入图片描述

那么问题可能出在上位机的IP设置上,找到网络适配器设置,选择与PMAC连接的接口,按下图设置,最后单击确定。(注意:更改适配器的设置可能会导致下次网线连接此口时无法进行网络访问,那时需要恢复设置为【自动获得IP地址】),修改完毕后重复step2。如果仍然连接失败,断开网络再试试。 😇

在这里插入图片描述

4. 创建自己的伺服控制项目

        创建项目的过程跟VS中project的创建几乎无差,在此不再赘述,参见Power PMAC IDE手册P139。项目目录结构如下:


在这里插入图片描述

        为防止在调试过程中由于参数设置不当导致伺服电机或驱动器的损坏,我们可以通过设置虚轴的方式进行模拟调试。
        虚轴设置如下:

//来自官方论坛某大神
// Activate servo algorithms for motors
Motor[1].ServoCtrl=1
Motor[2].ServoCtrl=1
Motor[3].ServoCtrl=1
Motor[4].ServoCtrl=1
Motor[5].ServoCtrl=1
Motor[6].ServoCtrl=1
Motor[7].ServoCtrl=1
Motor[8].ServoCtrl=1

// Write servo output to user shared memory registers
Motor[1].pDac=Sys.Idata[1].a    // Same as EncTable[1].pEnc
Motor[2].pDac=Sys.Idata[2].a    // Same as EncTable[2].pEnc
Motor[3].pDac=Sys.Idata[3].a    // Same as EncTable[3].pEnc
Motor[4].pDac=Sys.Idata[4].a    // Same as EncTable[4].pEnc
Motor[5].pDac=Sys.Idata[5].a    // Same as EncTable[5].pEnc
Motor[6].pDac=Sys.Idata[6].a    // Same as EncTable[6].pEnc
Motor[7].pDac=Sys.Idata[7].a    // Same as EncTable[7].pEnc
Motor[8].pDac=Sys.Idata[8].a    // Same as EncTable[8].pEnc

// Encoder conversion table entry to read and integrate this
EncTable[1].type=1            // 32-bit register read
EncTable[1].pEnc=Sys.idata[1].a    // Same as Motor[1].pDac
EncTable[1].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[1].index1=0            // No shift right of source data
EncTable[1].index2=0            // No shift left of source data
EncTable[1].index3=0            // No accel limiting
EncTable[1].index4=1            // Single integration
EncTable[1].PrevDelta=0        // No bias before integration
EncTable[1].MaxDelta=0        // No velocity limit
EncTable[1].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[2].type=1            // 32-bit register read
EncTable[2].pEnc=Sys.idata[2].a    // Same as Motor[2].pDac
EncTable[2].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[2].index1=0            // No shift right of source data
EncTable[2].index2=0            // No shift left of source data
EncTable[2].index3=0            // No accel limiting
EncTable[2].index4=1            // Single integration
EncTable[2].PrevDelta=0        // No bias before integration
EncTable[2].MaxDelta=0        // No velocity limit
EncTable[2].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[3].type=1            // 32-bit register read
EncTable[3].pEnc=Sys.idata[3].a    // Same as Motor[3].pDac
EncTable[3].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[3].index1=0            // No shift right of source data
EncTable[3].index2=0            // No shift left of source data
EncTable[3].index3=0            // No accel limiting
EncTable[3].index4=1            // Single integration
EncTable[3].PrevDelta=0        // No bias before integration
EncTable[3].MaxDelta=0        // No velocity limit
EncTable[3].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[4].type=1            // 32-bit register read
EncTable[4].pEnc=Sys.idata[4].a    // Same as Motor[4].pDac
EncTable[4].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[4].index1=0            // No shift right of source data
EncTable[4].index2=0            // No shift left of source data
EncTable[4].index3=0            // No accel limiting
EncTable[4].index4=1            // Single integration
EncTable[4].PrevDelta=0        // No bias before integration
EncTable[4].MaxDelta=0        // No velocity limit
EncTable[4].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[5].type=1            // 32-bit register read
EncTable[5].pEnc=Sys.idata[5].a    // Same as Motor[5].pDac
EncTable[5].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[5].index1=0            // No shift right of source data
EncTable[5].index2=0            // No shift left of source data
EncTable[5].index3=0            // No accel limiting
EncTable[5].index4=1            // Single integration
EncTable[5].PrevDelta=0        // No bias before integration
EncTable[5].MaxDelta=0        // No velocity limit
EncTable[5].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[6].type=1            // 32-bit register read
EncTable[6].pEnc=Sys.idata[6].a    // Same as Motor[6].pDac
EncTable[6].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[6].index1=0            // No shift right of source data
EncTable[6].index2=0            // No shift left of source data
EncTable[6].index3=0            // No accel limiting
EncTable[6].index4=1            // Single integration
EncTable[6].PrevDelta=0        // No bias before integration
EncTable[6].MaxDelta=0        // No velocity limit
EncTable[6].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[7].type=1            // 32-bit register read
EncTable[7].pEnc=Sys.idata[7].a    // Same as Motor[7].pDac
EncTable[7].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[7].index1=0            // No shift right of source data
EncTable[7].index2=0            // No shift left of source data
EncTable[7].index3=0            // No accel limiting
EncTable[7].index4=1            // Single integration
EncTable[7].PrevDelta=0        // No bias before integration
EncTable[7].MaxDelta=0        // No velocity limit
EncTable[7].ScaleFactor=1/65536    // 32 bits -> 16 bits

EncTable[8].type=1            // 32-bit register read
EncTable[8].pEnc=Sys.idata[8].a    // Same as Motor[8].pDac
EncTable[8].pEnc1=Sys.pushm        // Dummy read (not used)
EncTable[8].index1=0            // No shift right of source data
EncTable[8].index2=0            // No shift left of source data
EncTable[8].index3=0            // No accel limiting
EncTable[8].index4=1            // Single integration
EncTable[8].PrevDelta=0        // No bias before integration
EncTable[8].MaxDelta=0        // No velocity limit
EncTable[8].ScaleFactor=1/65536    // 32 bits -> 16 bits

// Read the encoder conversion table result as feedback
Motor[1].pEnc=EncTable[1].a        // Position loop feedback source
Motor[1].pEnc2=EncTable[1].a    // Velocity loop feedback source
Motor[2].pEnc=EncTable[2].a        // Position loop feedback source
Motor[2].pEnc2=EncTable[2].a    // Velocity loop feedback source
Motor[3].pEnc=EncTable[3].a        // Position loop feedback source
Motor[3].pEnc2=EncTable[3].a    // Velocity loop feedback source
Motor[4].pEnc=EncTable[4].a        // Position loop feedback source
Motor[4].pEnc2=EncTable[4].a    // Velocity loop feedback source
Motor[5].pEnc=EncTable[5].a        // Position loop feedback source
Motor[5].pEnc2=EncTable[5].a    // Velocity loop feedback source
Motor[6].pEnc=EncTable[6].a        // Position loop feedback source
Motor[6].pEnc2=EncTable[6].a    // Velocity loop feedback source
Motor[7].pEnc=EncTable[7].a        // Position loop feedback source
Motor[7].pEnc2=EncTable[7].a    // Velocity loop feedback source
Motor[8].pEnc=EncTable[8].a        // Position loop feedback source
Motor[8].pEnc2=EncTable[8].a    // Velocity loop feedback source


// Disable overtravel limit inputs
// May be needed if there are no physical switches present
Motor[1].pLimits=0
Motor[2].pLimits=0
Motor[3].pLimits=0
Motor[4].pLimits=0
Motor[5].pLimits=0
Motor[6].pLimits=0
Motor[7].pLimits=0
Motor[8].pLimits=0

// Disable amplifier enable output
// May be needed if channel is also connected to real amplifier
Motor[1].pAmpEnable=0
Motor[2].pAmpEnable=0
Motor[3].pAmpEnable=0
Motor[4].pAmpEnable=0
Motor[5].pAmpEnable=0
Motor[6].pAmpEnable=0
Motor[7].pAmpEnable=0
Motor[8].pAmpEnable=0

// Disable amplifier fault input
// May be needed if channel is also connected to real amplifier
Motor[1].pAmpFault=0
Motor[2].pAmpFault=0
Motor[3].pAmpFault=0
Motor[4].pAmpFault=0
Motor[5].pAmpFault=0
Motor[6].pAmpFault=0
Motor[7].pAmpFault=0
Motor[8].pAmpFault=0

// Set derivative gain term in servo loop to zero
// This is a Type 1 servo (single integration); does not need Kd
Motor[1].Servo.Kvfb=0
Motor[2].Servo.Kvfb=0
Motor[3].Servo.Kvfb=0
Motor[4].Servo.Kvfb=0
Motor[5].Servo.Kvfb=0
Motor[6].Servo.Kvfb=0
Motor[7].Servo.Kvfb=0
Motor[8].Servo.Kvfb=0
// Lower proportional gain term from default
Motor[1].Servo.Kp=1
Motor[2].Servo.Kp=1
Motor[3].Servo.Kp=1
Motor[4].Servo.Kp=1
Motor[5].Servo.Kp=1
Motor[6].Servo.Kp=1
Motor[7].Servo.Kp=1
Motor[8].Servo.Kp=1
// Add integral gain to force to zero error
Motor[1].Servo.Ki=0.01
Motor[2].Servo.Ki=0.01
Motor[3].Servo.Ki=0.01
Motor[4].Servo.Ki=0.01
Motor[5].Servo.Ki=0.01
Motor[6].Servo.Ki=0.01
Motor[7].Servo.Ki=0.01
Motor[8].Servo.Ki=0.01
// Set deadband zone to zero
Motor[1].Servo.BreakPosErr=0
Motor[2].Servo.BreakPosErr=0
Motor[3].Servo.BreakPosErr=0
Motor[4].Servo.BreakPosErr=0
Motor[5].Servo.BreakPosErr=0
Motor[6].Servo.BreakPosErr=0
Motor[7].Servo.BreakPosErr=0
Motor[8].Servo.BreakPosErr=0
// Add feedforward to minimize tracking error
Motor[1].Servo.Kvff=1
Motor[1].Servo.Kaff=1
Motor[2].Servo.Kvff=1
Motor[2].Servo.Kaff=1
Motor[3].Servo.Kvff=1
Motor[3].Servo.Kaff=1
Motor[4].Servo.Kvff=1
Motor[4].Servo.Kaff=1
Motor[5].Servo.Kvff=1
Motor[5].Servo.Kaff=1
Motor[6].Servo.Kvff=1
Motor[6].Servo.Kaff=1
Motor[7].Servo.Kvff=1
Motor[7].Servo.Kaff=1
Motor[8].Servo.Kvff=1
Motor[8].Servo.Kaff=1

        我们把上述代码拷贝到PMAC脚本语言目录下的全局变量定义中,如下图所示:


在这里插入图片描述

        然后开始写入运动程序,在Motion Programs目录下的prog1.pmc文件中写入运动程序代码,此例中我们以两轴电机绘制矩形为例,把代码写进文件并保存。

/****************************************/
//By Jack Soong
//Time:2019.1.21
&1 //定义座标系1
#1->X; //将电机指定给x,y轴
#2->Y;

 open prog 1 
// --------------------User Code Goes Here------------------------
linear  //直线mode
abs	    //绝对值编程
tm 500  //插补加速参数设置
ta 100
ts 200
dwell 0 Gather.Enable = 2;dwell  0//将数据收集到先前plot设置元素的缓冲区
X0 Y0;
X0 Y100;
X100 Y100;
X100 Y0;
X0 Y0;
dwell 100; //延时
Gather.Enable = 0;dwell 0  //关闭收集
close
/****************************************/

        完成上述步骤后,在解决方案名称上右击选择构建并下载所有程序,将程序下载到CK3M中,注意:如果连接实际硬件,需要在配置完电机后先选择映射PowerPMAC变量。


        OK!接下来我们就要让它动起来了,首先打开数据收集功能,在代码中我们已经开启了数据收集并保存到缓存中,这是我们需要在程序真正运行之前打开数据收集界面(位于菜单栏中,即绘图功能),如下图所示。



        在终端中输入"#1…2j/“命令先使能电机,然后用命令”&1 b1 r"运行我们的运动程序,在程序运行过程中,绘图界面上传数据按钮下方的进度条会随着程序的执行过程而有所变化,待进度条满后点击上传数据,并把要绘制的值添加到座标轴(选中要添加的值,然后点击>>按钮将其添加到绘制栏,如果需要删除,则在绘制栏中选中该选项点击<<即可删除),此处我们以Motion[1].Cmd Position(即电机1的命令位置,换句话说就是理想输出位置)为横座标,以Motion[2].Cmd Position为纵座标绘制图形,得到的绘制图形如下,我们可以看到绘制的矩形似乎不太听话 😂 😂 😂,淡定点老铁,所画图形并非方方正正的矩形的原因在于:Power PMAC中有一个状态位(Coord[x].NoBlend)是用来控制各运动点之间是否进行插补的,Coord[x].NoBlend默认为0,即使能Move Blending,因此走出来的矩形并非理想形状,如果设置Coord[x].NoBlend=1那么这个矩形就比较听话啦!


5. 学习途径

[1]前文提到的手册:软件参考手册、用户使用手册(都说手册是最好的教程,但是这个手册博主个人感觉…… 😂 😂 😂)
[2]官方视频教程(发布在Youtube,需要怎么访问你懂的,楼主已经刷过一遍,感觉没啥用,前文提到的5天培训PPT便是该教程配套的)
[3]官方论坛(活跃人数少,但专业,可能由于收购原因?前段时间服务器直接关闭,近期才重新启动)
[4]工控论坛PMAC专区(人数多,回复不及时,目前博主在此论坛没有找到有价值的ppmac资料,其他版本PMAC资料相对较多)
[5]文大侠博客
[6]Jackie的储物袋的博客

后记

        这几周可谓是历经千辛万险,终于有所入门,可离结题还是遥遥无期,虽然困难重重,但是问题的解决总会伴随着慢慢的成就感,越挫越勇才能成就更好的自己~
        第一次写博文,干货不多,只提供给大家一个初步入门的路子,顺便也当做学习笔记了。在此要感谢北京机科国创的李工、欧姆龙技术支持周工以及我的林副总师兄提供的帮助。

        下期预告:Power PMAC中运动程序的编写


	 [1]: https://baike.baidu.com/item/PMAC/1955812?fr=aladdin
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章