文章目录
运动控制之电子凸轮修改凸轮点
一. 根据制袋机双切R角工艺需求
-
工艺背景:
制袋行业有切圆角袋工艺需求(切废边-行业内称为R角)切刀是0到360度变化,电机旋转转换成切刀上下运动。
双切工艺需求:
-
切刀第一个周期,切前一个袋子的边;切刀第二个周期且后一个袋子的边。
-
也就是说移刀第一个周期不动,第二个周期微动,微动到位后等待切刀切下,然后再等刀抬起后,返回原来位置。
-
切刀切料角度120度-240度,在此区间移刀不能运动。
-
移刀微动距离一般是1-5mm,客户要求可根据实际情况自行修改设置。
根据上面要求呢,我们一般将主轴设置周期从360改成720,方便规划电子凸轮曲线。
使用电子凸轮后,将客户设备双切速度从原来80刀/min提升刀160刀/min,达到机械极限。
二.凸轮曲线修改常用方法
注意 : 仅针对编译为多项式(XYVA)。
-
通过改凸轮曲线的主从轴缩放比例或者偏置。
-
新建多个凸轮曲线,对CAM曲线进行切换。
-
程序中动态修改,仅修改中间的关键点(凸轮末点修改or凸轮曲线运行中修改)。
-
程序中动态修改,修改首未关键点及关键点个数,需要重新触发MC_TableSelect。
-
使用程序新建凸轮表代码,实现电子凸轮基本运动。
我们讲的凸轮表切换、关键点修改、程序新建电子凸轮,这些方法没有本质区别,总之都是“趁曲线不注意,把凸轮表改了。
学习目标
-
通过修改从轴缩放比例,实现移刀曲线修改。
-
在静态状态切换凸轮表 。
-
在来点时动态切换凸轮表。
-
在凸轮末点修改关键点,下一周期生效 。
-
在凸轮运行中修改关键点,当前周期生效。
-
凸轮末点修改 凸轮关键点个数,不修改首末关键点,不需要重新触发MC CamTableselect。
三. Cam表MC_CAM_REF类型
在Codesys中,对每一个CAM 表都有描述该CAM 表的数据结构,描述该CAM 表的特征数据。下图为“CAM”凸轮表的描述数据结构,请注意其结构各变量名称:
注意::我们在声明CAM 凸轮表时,系统自动默认声明了全局变量类型的CAM 数据结构,同时声明了CAM_A[i] 数组。可以在用户程序中,修改CAM 凸轮表关键点个数或坐标:
总结:我们其实可以不通过application右键添加凸轮表,而是通过程序手动新建凸轮表数据结构,然后新建对应的数组,给当前数据结构赋值。
四. 修改电子曲线的原则总结
什么是好的凸轮曲线?
-
适合的凸轮由线就是好的凸轮曲线。
什么样算“适合”?
-
满足精度要求的。
-
满足效率要求。
-
满足工艺功能要求。
-
噪音小,运行流畅的。
位置是描述的运行轨迹 (精度),速度是描述的移动快慢 (效率),加速度是描述的力的变化 (振动和噪音),加加速度是描述的力的变化速度 (振动和噪音的频率)。
好的凸轮曲线特点:
-
位置连续。
-
速度连续,且速度比较小。
-
加速度连续,且幅度较小。
-
加加速度幅度小。
五. 曲线规划以及修改凸轮表
5.1. 轴配置设计
5.2. 凸轮表设计
5.3. 代码框架设计
这里展示出所有的相关变量、已经目录结构。
-
GVL_Var
// {attribute 'qualified_only'}
VAR_GLOBAL
gsc_InnerIO : SCTY_INNER_IO;
gf_TotalAccDec : REAL := 100; // 全局加速度/减速度
gb_MasterVelocityExecute : BOOL; // 虚拟主轴:速度运行命令
gf_MasterVelocityValue : REAL := 100; // 虚拟主轴:速度运行参数
gi_MasterDirection : INT := 1; // 虚拟主轴:速度运行方向
gb_MasterStop : BOOL; // 虚拟主轴:停止命令
gb_MasterStopDone : BOOL; // 虚拟主轴:停止命令完成
gb_FilmGearExecute : BOOL; // 实际主轴:电子齿轮耦合
gb_FilmGearSyn : BOOL; // 实际主轴:电子齿轮同步中
gdi_FilmNumerator : DINT := 10000; // 实际主轴:电子齿轮比分子
gudi_FilmRightDenominator : UDINT := 10000; // 实际主轴:电子齿轮比分母
gb_FilmGearOutExecute : BOOL; // 实际主轴:电子齿轮解耦合
gb_FilmGearOutDone : BOOL; // 实际主轴:电子齿轮解耦合完成
gb_FilmStop : BOOL; // 实际主轴:停止命令
gb_FilmStopDone : BOOL; // 实际主轴:停止命令完成
gb_KnifeCamTabExecute : BOOL; // 实际刀轴:电子凸轮Cam表选择
gb_KnifeCamTabDone : BOOL; // 实际刀轴:电子凸轮Cam表选择完成
gb_KnifeCamExecute : BOOL; // 实际刀轴:电子凸轮耦合
gb_KnifeCamSyn : BOOL; // 实际刀轴:电子凸轮同步中
gb_EndOfProfile : BOOL; // 实际刀轴:电子凸轮凸轮周期完成信号
gb_KnifeCamOutExecute : BOOL; // 实际刀轴:电子凸轮解耦合
gb_KnifeCamOutDone : BOOL; // 实际刀轴:电子凸轮解耦合完成
gb_KnifeStop : BOOL; // 实际刀轴:停止命令
gb_KnifeStopDone : BOOL; // 实际刀轴:停止命令完成
gf_SlaveScaling : REAL; // 电子凸轮:从轴缩放比例
gf_KnifeMoveDistance : REAL := 1; // 电子凸轮:从轴移刀距离
gmc_Cam_Ref : MC_CAM_REF;
gi_ModifiCamTableMode : INT := 1; // 凸轮表修改模式:1=通过从轴比例缩放
gi_CamTableId : INT := 1; // 凸轮表ID选择
gb_CamSwitchTest : BOOL;
gb_CamTest : bool;
END_VAR
-
SCTY_INNER_IO
TYPE SCTY_INNER_IO :
STRUCT
gb_FirstOn : BOOL; // 首次执行
gb_PowerOn : BOOL; // 持续执行
gb_SingleStep : BOOL; // 单步执行
gb_MaskSingleStep : BOOL; // 屏蔽单步执行
gb_Reset : BOOL; // 复位
gb_Pause : BOOL; // 暂停
gb_JerkStop : BOOL; // 急停
gb_Start : BOOL; // 启动
gb_Stop : BOOL; // 停止
gi_SystemState : SINT;
END_STRUCT
END_TYPE
-
PRG_TaskEct_No3、PRG_TaskEct_No2、PRG_TaskEct_No1局部变量
PROGRAM PRG_TaskEct_No3
VAR
vmc_MasterPower : MC_Power;
vmc_FilmPower : MC_Power;
vmc_KnifePower : MC_Power;
vmc_MasterStop : MC_Stop;
vmc_FilmStop : MC_Stop;
vmc_KnifeStop : MC_Stop;
vmc_MasterVelocity : MC_MoveVelocity;
vmc_FilmGearIn : MC_GearIn;
vmc_FilmGearOut : MC_GearOut;
vmc_KnifeCamTableSelect : MC_CamTableSelect;
vmc_KnifeCamIn : MC_CamIn;
vmc_KnifeCamOut : MC_CamOut;
vf_SlaveScalingBuffer : REAL;
vf_EndBuffer : REAL;
vrp_Test : R_TRIG;
END_VAR
5.4. 修改凸轮曲线
5.4.1. 通过修改从轴比例缩放修改凸轮曲线
-
PRG_TaskEct_No1.A03_LogicalCode逻辑代码:
// 逻辑程序编写
gi_ModifiCamTableMode := 1;
CASE gi_ModifiCamTableMode OF
01:
gmc_Cam_Ref := Cam_1mm_No1;
gf_SlaveScaling := gf_KnifeMoveDistance / 1.0; // 1.0是Cam_1mm_No1的基准
IF (R_Slave_Knife.nAxisState = 3) OR gb_EndOfProfile THEN
gb_KnifeCamTabExecute := (NOT gb_KnifeCamSyn) OR (gf_SlaveScaling <> vf_SlaveScalingBuffer);
vf_SlaveScalingBuffer := gf_SlaveScaling;
END_IF
END_CASE
5.4.2. 通过切换Cam表修改凸轮曲线
新建MC_CAM_REF凸轮表类型的全局变量,在程序中根据需求进行切换,一般凸轮表直接切换,应用在工艺不复杂,情况比较少的场景中,一般也就是几个凸轮表切换就能满足工艺需求场景。
在程序中根据进行凸轮表的选择切换常用方法有两种方法:
-
在整机待机,静止状态下切换电子凸轮表。
-
在电子凸轮周期末点,切换电子凸轮表。
-
PRG_TaskEct_No2.A03_LogicalCode逻辑代码:
// 逻辑程序编写
gi_ModifiCamTableMode := 02;
CASE gi_ModifiCamTableMode OF
02:
// 手动启动凸轮
IF (R_Slave_Knife.nAxisState = 3) OR gb_EndOfProfile THEN
IF gi_CamTableId = 1 THEN
gmc_Cam_Ref := Cam_1mm_No2;
ELSIF gi_CamTableId = 2 THEN
gmc_Cam_Ref := Cam_2mm_No2;
ELSIF gi_CamTableId = 3 THEN
gmc_Cam_Ref := Cam_3mm_No2;
ELSIF gi_CamTableId = 4 THEN
gmc_Cam_Ref := Cam_4mm_No2;c
ELSIF gi_CamTableId = 5 THEN c
gmc_Cam_Ref := Cam_5mm_No2;
END_IF
END_IF
END_CASE
5.5. 修改凸轮曲线关键点
5.5.1.凸轮周期末点或停机修改关键点
我们在声明CAM凸轮表时,系统自动默认声明了全局变量类型的CAM数据结构,同时声明了CAM_A[i]数组,可以在用户程序中,修改CAM凸轮关键点个数或者坐标。
-
PRG_TaskEct_No3.A03_LogicalCode逻辑代码:
// 逻辑程序编写
gi_ModifiCamTableMode := 03;
CASE gi_ModifiCamTableMode OF
03:
gmc_Cam_Ref := Cam_1mm_No1;
// 凸轮末点信号时修改关键点,下一个凸轮周期生效(注意不是扫描周期,是凸轮周期)。
IF (R_Slave_Knife.nAxisState = 3) OR gb_EndOfProfile THEN
gb_KnifeCamTabExecute := (NOT gb_KnifeCamSyn) ;
// 第一个关键点
Cam_1mm_No1_A[0].dX := 0.0;
Cam_1mm_No1_A[0].dY := 0.0;
Cam_1mm_No1_A[0].dV := 0.0;
Cam_1mm_No1_A[0].dA := 0.0;
// 第二个关键点
Cam_1mm_No1_A[1].dX := 360.0;
Cam_1mm_No1_A[1].dY := 0.0;
Cam_1mm_No1_A[1].dV := 0.0;
Cam_1mm_No1_A[1].dA := 0.0;
// 第三个关键点
Cam_1mm_No1_A[2].dX := 440.0;
Cam_1mm_No1_A[2].dY := gf_KnifeMoveDistance;
Cam_1mm_No1_A[2].dV := 0.0;
Cam_1mm_No1_A[2].dA := 0.0;
// 第四个关键点
Cam_1mm_No1_A[3].dX := 640.0;
Cam_1mm_No1_A[3].dY := gf_KnifeMoveDistance;
Cam_1mm_No1_A[3].dV := 0.0;
Cam_1mm_No1_A[3].dA := 0.0;
// 第五个关键点
Cam_1mm_No1_A[4].dX := 720.0;
Cam_1mm_No1_A[4].dY := 0.0;
Cam_1mm_No1_A[4].dV := 0.0;
Cam_1mm_No1_A[4].dA := 0.0;
END_IF;
END_CASE
5.5.2. 运行中修改非当前段关键点
总共有5个关键点,除掉首末关键点(一般也不改首末关键点),不需要重新触发MCCamTableSelect如果要改首末关键点的话,要重新触发MC CamTableSelect。
-
当从轴运行在第一段,可以修改第三个或者第四个关键点的XYVZ坐标。
-
当从轴运行在第二段,可以修改第四个关键点的 XYVA坐标。
-
当从轴运行在第三段,可以修改的第二个关键点的XYVA坐标。
-
当从轴运行在第四段,可以修改第二个或者第三个关键点的XYVZ坐标。
总结一下:“趁曲线不注意的时候,修改掉关键点”,实际上就是修改关键点时,别影响到当前正在运行的段,因为程序是周期扫描的,每个周期其实都会根据主轴位置以及电子凸轮曲线对应的数学函数(一般是五次曲线 poy)取解算从轴位置,所以一般我们修改电子凸轮曲线,只需要保证当前关键点 不在当前运行段就能修改了:
-
PRG_TaskEct_No3.A03_LogicalCode逻辑代码:
// 逻辑程序编写
gi_ModifiCamTableMode := 04;
CASE gi_ModifiCamTableMode OF
04:
// 当前凸轮周期,修改非运行段凸轮关键点,当前凸轮周期生效
gmc_Cam_Ref := Cam_1mm_No1;
IF (R_Slave_Knife.nAxisState = 3) THEN
gb_KnifeCamTabExecute := (NOT gb_KnifeCamSyn) ;
END_IF
// 运行在第三个关键点之前,此时可以修改第四个关键点。
IF (V_Master.fSetPosition < 440.0) THEN
// 第四个关键点
Cam_1mm_No1_A[3].dX := 640.0;
Cam_1mm_No1_A[3].dY := gf_KnifeMoveDistance;
Cam_1mm_No1_A[3].dV := 0.0;
Cam_1mm_No1_A[3].dA := 0.0;
// 运行在第一段凸轮曲线或者第四段凸轮曲线
ELSIF (V_Master.fSetPosition < 360.0) OR (V_Master.fSetPosition > 640) THEN
// 第三个关键点
Cam_1mm_No1_A[2].dX := 440.0;
Cam_1mm_No1_A[2].dY := gf_KnifeMoveDistance;
Cam_1mm_No1_A[2].dV := 0.0;
Cam_1mm_No1_A[2].dA := 0.0;
END_IF
END_CASE
注意:运行时修改,在修改时,当前的凸轮周期会发生形变,不能保证对每一种工艺都有效果,索引要慎用。
5.5.3. 修改凸轮曲线关键点个数
我们一般情况下,很少会修改关键点的个数。
-
PRG_TaskEct_No3.A03_LogicalCode逻辑代码:
gi_ModifiCamTableMode := 05;
CASE gi_ModifiCamTableMode OF
05:
// 凸轮末点修改,关键点个数,不修改末点关键点,不需要重新触发MC_CamTableSelect
IF (R_Slave_Knife.nAxisState = 3) THEN
gb_KnifeCamTabExecute := (NOT gb_KnifeCamSyn) ;
END_IF
IF gb_EndOfProfile AND gb_CamSwitchTest THEN
Cam_1mm_No1.nElements := 5;
Cam_1mm_No1.byType := 3;
Cam_1mm_No1.xStart := 0.0;
Cam_1mm_No1.xEnd := 720.0;
// 第一个关键点
Cam_1mm_No1_A[0].dX := 0.0;
Cam_1mm_No1_A[0].dY := 0.0;
Cam_1mm_No1_A[0].dV := 0.0;
Cam_1mm_No1_A[0].dA := 0.0;
// 第二个关键点
Cam_1mm_No1_A[1].dX := 360.0;
Cam_1mm_No1_A[1].dY := 0.0;
Cam_1mm_No1_A[1].dV := 0.0;
Cam_1mm_No1_A[1].dA := 0.0;
// 第三个关键点
Cam_1mm_No1_A[2].dX := 440.0;
Cam_1mm_No1_A[2].dY := 1;
Cam_1mm_No1_A[2].dV := 0.0;
Cam_1mm_No1_A[2].dA := 0.0;
// 第四个关键点
Cam_1mm_No1_A[3].dX := 640.0;
Cam_1mm_No1_A[3].dY := 1;
Cam_1mm_No1_A[3].dV := 0.0;
Cam_1mm_No1_A[3].dA := 0.0;
// 第五个关键点
Cam_1mm_No1_A[4].dX := 720.0;
Cam_1mm_No1_A[4].dY := 0.0;
Cam_1mm_No1_A[4].dV := 0.0;
Cam_1mm_No1_A[4].dA := 0.0;
ELSIF gb_EndOfProfile AND (NOT gb_CamSwitchTest) THEN
Cam_1mm_No1.nElements := 3;
Cam_1mm_No1.byType := 3;
Cam_1mm_No1.xStart := 0.0;
Cam_1mm_No1.xEnd := 720.0;
// 第一个关键点
Cam_1mm_No1_A[0].dX := 0.0;
Cam_1mm_No1_A[0].dY := 0.0;
Cam_1mm_No1_A[0].dV := 0.0;
Cam_1mm_No1_A[0].dA := 0.0;
// 第二个关键点
Cam_1mm_No1_A[1].dX := 360.0;
Cam_1mm_No1_A[1].dY := 1.0;
Cam_1mm_No1_A[1].dV := 0.0;
Cam_1mm_No1_A[1].dA := 0.0;
// 第三个关键点
Cam_1mm_No1_A[2].dX := 720.0;
Cam_1mm_No1_A[2].dY := 0.0;
Cam_1mm_No1_A[2].dV := 0.0;
Cam_1mm_No1_A[2].dA := 0.0;
END_IF;
gmc_Cam_Ref := Cam_1mm_No1;
END_CASE
5.5.2. 修改凸轮曲线末尾长度
如果需要修改首末关键点的坐标,需要重新触发MC_CamTableSelect。
-
PRG_TaskEct_No3.A03_LogicalCode逻辑代码:
gi_ModifiCamTableMode := 06;
CASE gi_ModifiCamTableMode OF
06:
IF gb_EndOfProfile AND gb_CamSwitchTest THEN
Cam_1mm_No1.nElements := 5;
Cam_1mm_No1.byType := 3;
Cam_1mm_No1.xStart := 0.0;
Cam_1mm_No1.xEnd := 720.0;
// 第一个关键点
Cam_1mm_No1_A[0].dX := 0.0;
Cam_1mm_No1_A[0].dY := 0.0;
Cam_1mm_No1_A[0].dV := 0.0;
Cam_1mm_No1_A[0].dA := 0.0;
// 第二个关键点
Cam_1mm_No1_A[1].dX := 360.0;
Cam_1mm_No1_A[1].dY := 0.0;
Cam_1mm_No1_A[1].dV := 0.0;
Cam_1mm_No1_A[1].dA := 0.0;
// 第三个关键点
Cam_1mm_No1_A[2].dX := 440.0;
Cam_1mm_No1_A[2].dY := 1;
Cam_1mm_No1_A[2].dV := 0.0;
Cam_1mm_No1_A[2].dA := 0.0;
// 第四个关键点
Cam_1mm_No1_A[3].dX := 640.0;
Cam_1mm_No1_A[3].dY := 1;
Cam_1mm_No1_A[3].dV := 0.0;
Cam_1mm_No1_A[3].dA := 0.0;
// 第五个关键点
Cam_1mm_No1_A[4].dX := 720.0;
Cam_1mm_No1_A[4].dY := 0.0;
Cam_1mm_No1_A[4].dV := 0.0;
Cam_1mm_No1_A[4].dA := 0.0;
ELSIF gb_EndOfProfile AND (NOT gb_CamSwitchTest) THEN
Cam_1mm_No1.nElements := 5;
Cam_1mm_No1.byType := 3;
Cam_1mm_No1.xStart := 0.0;
Cam_1mm_No1.xEnd := 360.0;
// 第一个关键点
Cam_1mm_No1_A[0].dX := 0.0;
Cam_1mm_No1_A[0].dY := 0.0;
Cam_1mm_No1_A[0].dV := 0.0;
Cam_1mm_No1_A[0].dA := 0.0;
// 第二个关键点
Cam_1mm_No1_A[1].dX := 180.0;
Cam_1mm_No1_A[1].dY := 0.0;
Cam_1mm_No1_A[1].dV := 0.0;
Cam_1mm_No1_A[1].dA := 0.0;
// 第三个关键点
Cam_1mm_No1_A[2].dX := 240.0;
Cam_1mm_No1_A[2].dY := 1;
Cam_1mm_No1_A[2].dV := 0.0;
Cam_1mm_No1_A[2].dA := 0.0;
// 第四个关键点
Cam_1mm_No1_A[3].dX := 340.0;
Cam_1mm_No1_A[3].dY := 1;
Cam_1mm_No1_A[3].dV := 0.0;
Cam_1mm_No1_A[3].dA := 0.0;
// 第五个关键点
Cam_1mm_No1_A[4].dX := 360.0;
Cam_1mm_No1_A[4].dY := 0.0;
Cam_1mm_No1_A[4].dV := 0.0;
Cam_1mm_No1_A[4].dA := 0.0;
END_IF;
// 赋值凸轮表
gmc_Cam_Ref := Cam_1mm_No1;
vrp_Test(CLK:= gb_CamTest);
gb_KnifeCamTabExecute := (vf_EndBuffer <> Cam_1mm_No1.xEnd) OR vrp_Test.Q;
vf_EndBuffer := Cam_1mm_No1.xEnd;
END_CASE