BeckHoff PLC –> 料筐(KLT Box)自动对中与抓取程序分析

料框自动对中与抓取程序是工业自动化中的典型应用,需要结合传感器检测、运动控制和逻辑判断实现精准操作。

                                       

目录

一、以下是编程的核心要领和关键点:

1.1、系统架构设计

1.2、传感器应用与信号处理

1.3、运动控制策略

1.4、校准算法与数学计算

1.5、错误处理与可靠性

1.6、调试与优化

1.7、编程规范与最佳实践

二、倍福PLC ST语言编的程序源码:

三、对以上源代码的分析

3.1 核心功能解析

1. 整体流程

2. 关键技术细节

3.2  局限性分析

1. 硬编码参数依赖

2. 错误处理能力有限

3. 传感器可靠性风险

4. 性能与效率问题

5. 缺乏柔性适配

3.3 改进建议

3.4 总结


一、以下是编程的核心要领和关键点:

1.1、系统架构设计

模块化设计

将程序分为初始化、检测、校准、抓取、异常处理等独立模块,提高可维护性。
使用状态机(如 CASE 语句)实现流程控制,确保步骤有序执行。

数据结构规划

定义轴位置、传感器状态、校准参数等数据类型。
使用全局变量或结构体存储关键数据(如 tCheckPos1tAlignementEndAxisXPos)。

1.2、传感器应用与信号处理

传感器选择与布局

位置检测:使用光电传感器、接近开关或激光测距仪检测料框边缘。
存在检测:通过对射式传感器或压力传感器确认料框是否被抓取。
角度检测:通过两个位置传感器的触发时间差计算料框偏移角度。

信号处理技巧

滤波处理:使用延时检测(如 Delay_SensorCheck)消除信号抖动。

st

// 示例:检测传感器信号稳定10ms后才确认有效
Delay_SensorCheck (IN:=(NOT bIN_AligneX_Sensor1 OR NOT bIN_AligneX_Sensor2), PT:=T#10MS, Q=>, ET=>);

 

超时机制:设置最大检测时间(如 Delay_SensorCheckAlarm),避免程序卡死。
冗余设计:多传感器交叉验证,提高可靠性。

1.3、运动控制策略

轴控制指令

使用运动控制功能块(如 MC_MoveAbsoluteF_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1)实现轴的精确定位。
配置合理的速度、加速度、精度参数:

st

AxisX_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
  iIn_idxElement:= idxLoad_AxisX, 
  rIn_Position:= targetPos, 
  rIn_Speed_In_Units:=50.0,  // 速度
  uiIn_ACCELPercent:=30,    // 加速度百分比
  rIN_Precision:= 0.1       // 定位精度
);

多轴协同控制

同步控制多轴(如 X/Y 轴联动)实现斜线或曲线运动。
在角度校准中,根据计算结果联动旋转轴(R 轴)和线性轴(X/Y 轴)。

安全机制

设置硬件 / 软件限位(HwLimitSwitchPos/NegSwLimitSwitchPos/Neg)防止轴超限。
在轴运动前检查驱动器状态(如 CommunicationReadyPowerOn)。

1.4、校准算法与数学计算

角度计算

通过两个传感器的触发位置计算偏移角度:

st

tAngle_Radian := ATAN((tCheckPos2 - tCheckPos1)/传感器间距);
tAngle := tAngle_Radian * 180.0 / PI;  // 弧度转角度

位置补偿

根据角度计算需要调整的 X/Y 轴偏移量:

st

// 示例:根据角度计算X/Y轴补偿量
IF tAngle > 0.5 THEN  // 逆时针旋转
  arstGV_Cell1_LoadAxisXOffset.rX := -100.0;  // X轴负方向补偿
  arstGV_Cell1_LoadAxisYOffset.rX := 100.0;   // Y轴正方向补偿
END_IF;

1.5、错误处理与可靠性

异常检测

监控传感器状态、轴位置和驱动器反馈,识别异常(如传感器超时、轴未到位)。
使用全局诊断变量(如 wINOUT_DIAGNOSE_Seq)记录错误类型。

恢复机制

设计错误恢复流程(如重试、回退到安全位置):

st

IF Delay_SensorCheckAlarm.Q THEN  // 传感器检测超时
  wINOUT_DIAGNOSE_Seq.3 := TRUE;  // 记录错误
  Step :=999;                     // 跳转到错误处理
END_IF;

安全停止

使用 MC_Halt 或 MC_Stop 功能块实现紧急暂停或有序停止:

st

// 示例:轴故障时触发紧急停止
IF ai.FROM_AXIS.Error THEN
  MC_Stop_Festo(Axis:=AxisX, Execute:=TRUE);
END_IF;

1.6、调试与优化

状态监控

添加调试输出点,实时显示轴位置、传感器状态和关键变量值。
使用 HMI 界面可视化程序运行状态。

参数调优

动态调整速度、加速度和精度参数,平衡效率与稳定性。
优化传感器触发阈值,减少误判。

性能优化

合并可并行执行的步骤(如多轴同时运动),缩短循环时间。
缓存常用位置数据,避免重复计算。

1.7、编程规范与最佳实践

结构化编程

使用函数块封装通用功能(如轴运动、传感器检测),提高代码复用性。
通过 CASE 或状态机实现清晰的流程控制。

注释与文档

添加详细注释说明关键逻辑和参数含义。
记录各步骤的功能和预期结果,便于后续维护。

版本控制

使用版本控制系统(如 Git)管理代码变更,便于追溯和协作。

二、倍福PLC ST语言编的程序源码:

   stVar_SEQ.bDisableTimeout 	:= TRUE;	

IF Step >=130 AND Step <=135 THEN 	
    Delay_SensorCheck (IN:=(NOT bIN_AligneX_Sensor1 OR NOT bIN_AligneX_Sensor2 ), PT:=T#10MS , Q=> , ET=> );	
END_IF	
     Delay_SensorCheckAlarm (IN:=Step =130, PT:=T#5S , Q=> , ET=> );	
IF Delay_SensorCheckAlarm.Q THEN
    wINOUT_DIAGNOSE_Seq.3 := TRUE;	// Alignement Sensor Shoul Be All On( Cable Label:2045B10(S18)+Cable Label:2046B10(S19)) 
END_IF
	 
IF stVar_SEQ.stXTimes.tTimeInStep >=T#20MS AND NOT stVar_SEQ.bTOK AND  Step =0 THEN
	  Delay.IN := FALSE;
	  Step :=10;
END_IF

IF NOT  stINOUT_SYS_CELL.stMODE.bAUTO_RUNNING THEN
	RETURN;
END_IF

CASE   Step  OF
  10 : // 清除缓存区 	
          tCheckPos1:=0.0;
          tCheckPos2:=0.0;
		  tAlignementEndAxisXPos:=0.0;
	      tAligneX_Sensor1_CheckOK  :=FALSE;
	      tAligneX_Sensor2_CheckOK  :=FALSE;
		  arstGV_Cell1_LoadAxisXOffset.rX:=0.0;
		  arstGV_Cell1_LoadAxisYOffset.rX:=0.0;
		  arstGV_Cell1_LoadAxisZOffset.rX:=0.0;
		  arstGV_Cell1_LoadAxisROffset.rX:=0.0; 	
		  arstGV_Cell1_LoadAxisXStop := FALSE;
	      arstGV_Cell1_LoadAxisYStop := FALSE;		  
	      Delay.IN := FALSE;	
	 IF NOT tAligneX_Sensor1_CheckOK AND NOT tAligneX_Sensor2_CheckOK AND NOT Delay.Q AND NOT arstGV_Cell1_LoadAxisXStop THEN // Wait Moved	 THEN
		 Step :=15; 
	 END_IF	
  15 : // 执行轴 移动到 待机位 (Z)
             Delay.IN := TRUE;	   
             Delay.PT := T#20MS;
       AxisZ_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:=  idxLoad_AxisZ, 
			rIn_Position:= stAxisPosZ[E_AxisPositions_Cell1.Standby].rX, 
			sIn_PosComment:= stAxisPosZ[E_AxisPositions_Cell1.Standby].sComment, 
			rIn_Speed_In_Units:=50.0 , 
			uiIn_ACCELPercent:=cACCEL , 
			uiIn_DECELPercent:=cDECL , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=  stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE); 			
	 IF  AxisZ_ExecuteEnd AND Delay.Q THEN // Wait Moved		 
          Step :=20; 
	 END_IF	
  20 : // Reset Timer
	     Delay.IN := FALSE; 
 	 IF  NOT Delay.Q THEN 
          Step :=25; 	 
	 END_IF	 	 
  25 : // 执行轴 移动到 检测位 (X)
             Delay.IN := TRUE;	   
             Delay.PT := T#20MS;
           arstGV_Cell1_LoadAxisXOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.KltBoxAliStart].rX;
  		 AxisX_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisX , 
			rIn_Position:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=cMedium	 , 
			uiIn_ACCELPercent:=30 , 
			uiIn_DECELPercent:=50 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE);  		
	 IF  AxisX_ExecuteEnd AND Delay.Q AND (NOT bIN_AligneX_Sensor1 OR NOT bIN_AligneX_Sensor2)THEN // Wait Moved
            Step :=30; 
	 ELSIF AxisX_ExecuteEnd AND Delay.Q AND bIN_AligneX_Sensor1 AND bIN_AligneX_Sensor2 THEN
		    wINOUT_DIAGNOSE_Seq.2 := TRUE;	// Alignement Sensor Shoul Not Be All On( Cable Label:2045B10(S18)+Cable Label:2046B10(S19))
		    Step :=999;		
	 END_IF	 
  30 : // Reset Timer
	     Delay.IN := FALSE; 
 	 IF  NOT Delay.Q THEN 
          Step :=35; 	 
	 END_IF	 	 
  35 : // 执行轴 移动到 检测位 (Y R)
             Delay.IN := TRUE;	   
             Delay.PT := T#50MS;
             arstGV_Cell1_LoadAxisYOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.KltBoxAliStart].rX;
			 arstGV_Cell1_LoadAxisROffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.NoOffset].rX;			 
  		 AxisY_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisY , 
			rIn_Position:= arstGV_Cell1_LoadAxisY_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisY_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=cMedium , 
			uiIn_ACCELPercent:=30 , 
			uiIn_DECELPercent:=50 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE);  
  		 AxisR_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisR , 
			rIn_Position:= arstGV_Cell1_LoadAxisR_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisR_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=cSlow , 
			uiIn_ACCELPercent:=30 , 
			uiIn_DECELPercent:=50 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE);  	
            AxisZ_ExecuteEnd:=FALSE;		
	 IF  AxisY_ExecuteEnd AND AxisR_ExecuteEnd AND Delay.Q THEN // Wait Moved		  
          Step :=40; 
	 END_IF	 
  40 : // Reset Timer
	     Delay.IN := FALSE; 
 	 IF  NOT Delay.Q THEN 
          Step :=45; 	 
	 END_IF	 	 
  45 : // 执行轴 移动到 检测位 (Z)
             Delay.IN := TRUE;	   
             Delay.PT := T#20MS;
         arstGV_Cell1_LoadAxisZOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.KltBoxPresent].rX;
  		 AxisZ_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisZ , 
			rIn_Position:= arstGV_Cell1_LoadAxisZ_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisZ_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=cMedium , 
			uiIn_ACCELPercent:=100 , 
			uiIn_DECELPercent:=100 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:= stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE); 
 		    AxisX_ExecuteEnd:=FALSE;
 		    AxisR_ExecuteEnd:=FALSE;			
	 IF  AxisZ_ExecuteEnd AND Delay.Q THEN // Wait Moved			
          Step :=50; 
	 END_IF	 
  50 : // Reset Timer
	     Delay.IN := FALSE; 
 	 IF  NOT Delay.Q THEN 
          Step :=55; 	 
	 END_IF	 	 
  55 : // Check Result
	     Delay.IN := TRUE; 
         Delay.PT := T#200MS; 
 	 IF Delay.Q AND bIN_KltInCraneGripper THEN  //当前位置有料筐
          Step :=100; 
     ELSIF Delay.Q AND NOT bIN_KltInCraneGripper THEN //当前位置无料筐	
	      stINOUT_ProcessHandshake.bOut_Handshake3  :=TRUE;	 // 强制更改计数 To Device2   
          Step :=60; 	 
	 END_IF	 
  60 : // Index - 1
        Pick_No:= Pick_No-1;
        Step :=65; 	
  65 : 
         Delay.IN := FALSE;
 	 IF NOT Delay.Q AND Pick_No> 0 THEN  //继续检测
          Step :=20;  
     ELSIF NOT Delay.Q AND Pick_No<= 0 THEN //当前位置无料筐	 直接结束Pick 功能  
          Step :=300; 		 
	 END_IF	 
  100 : // Reset Timer
	     Delay.IN := FALSE;
	     tAligneX_Sensor1_CheckOK  :=FALSE;
	     tAligneX_Sensor2_CheckOK  :=FALSE; 
 	 IF  NOT Delay.Q THEN 
          Step :=105; 	 
	 END_IF	 	 
   105 :	//  执行轴 移动到 校准结束位 ( X ) 记录两位置数据  
             Delay.IN := TRUE;	   
             Delay.PT := T#100MS;	 
             arstGV_Cell1_LoadAxisXOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.KltBoxAliEnd].rX;
  		 AxisX_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisX , 
			rIn_Position:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=2.0,
			uiIn_ACCELPercent:=2 , 
			uiIn_DECELPercent:=10 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=  stVar_SEQ.bRELEASE AND NOT arstGV_Cell1_LoadAxisXStop, 
			bIn_CMD_INIT:= FALSE);  			
     IF   AxisX_ExecuteEnd AND stGV_SYS_ELEMENTS.arstELEMENT[idxLoad_AxisX].stFeedBack.stSTATE.bIN_POSITION AND Delay.Q THEN // 检测失败	 
		    wINOUT_DIAGNOSE_Seq.3 := TRUE;	// Alignement Sensor Shoul Be All On( Cable Label:2045B10(S18)+Cable Label:2046B10(S19))
		    Step :=999;
	 ELSIF tAligneX_Sensor1_CheckOK AND tAligneX_Sensor2_CheckOK  THEN 
         Step :=110; 		 		 
	 END_IF			
   110 : //等待停止轴移动
			 Delay.IN := FALSE;
			 arstGV_Cell1_LoadAxisXStop := TRUE;
			 tAlignementEndAxisXPos:=PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.ACT_POS;	
		 IF NOT PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.IsMoving AND NOT Delay.Q AND tAlignementEndAxisXPos <> 0.0 THEN
		     Step :=120;			 
	     END_IF		 
   120 :
          tAngle_Radian  :=	ATAN ((tCheckPos2 -tCheckPos1)/300.0);
          tAngle :=	tAngle_Radian * 180.0 / 3.141592654;
	 IF  tAngle <= 0.5 AND tAngle >= -0.5 THEN // 不旋转
          Step :=130; 
	 ELSIF tAngle >0.5  THEN // 逆时针旋转		 
             Step :=121; 	
	 ELSIF tAngle < -0.5 THEN // 顺时针旋转		 
             Step :=121; 			  
	 END_IF
  121 : // 执行旋转轴( R )
           Delay.IN := TRUE;	   
           Delay.PT := T#20MS;
		   IF tAngle < 0 THEN
			   arstGV_Cell1_LoadAxisROffset.rX   := -tAngle + 0.2;	
	       ELSE
			   arstGV_Cell1_LoadAxisROffset.rX   := -tAngle - 0.2;				   
		   END_IF
  		 AxisR_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisR , 
			rIn_Position:= arstGV_Cell1_LoadAxisR_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisR_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=1.0,
			uiIn_ACCELPercent:=2 , 
			uiIn_DECELPercent:=100 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE); 
  		    AxisX_ExecuteEnd:=FALSE;				
	 IF   AxisR_ExecuteEnd AND Delay.Q THEN
          Step :=130; 	 
	 END_IF		 
  122 : // 执行旋转轴( R )
            Delay.IN := TRUE;	   
            Delay.PT := T#20MS;
		    arstGV_Cell1_LoadAxisROffset.rX   := +tAngle;
  		 AxisR_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisR , 
			rIn_Position:= arstGV_Cell1_LoadAxisR_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisR_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=1.0,
			uiIn_ACCELPercent:=2 , 
			uiIn_DECELPercent:=100 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE);  
 		    AxisX_ExecuteEnd:=FALSE;				
	 IF   AxisR_ExecuteEnd AND Delay.Q THEN
          Step :=130; 	 
	 END_IF		
  130 : // Reset Timer
	     Delay.IN := FALSE; 
		 arstGV_Cell1_LoadAxisXStop := FALSE;
		 Delay_SensorCheck.IN:=FALSE;
 	 IF  NOT Delay.Q AND NOT arstGV_Cell1_LoadAxisXStop AND NOT Delay_SensorCheck.Q THEN 
          Step :=135; 	 
	 END_IF	 	 
   135 ://  AxisX 负方向相对运行 100.0mm  等待检测 S18 和 S19 至少一个off
            Delay.IN := TRUE;	   
            Delay.PT := T#10MS;   			
		    arstGV_Cell1_LoadAxisXOffset.rX   :=  stGV_Cell1_AxisOffset[E_AxisPosData_Offset.KltBoxAliStart].rX;			 
  		 AxisX_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisX , 
			rIn_Position:=  tAlignementEndAxisXPos, //当前位置
			sIn_PosComment:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=1.0,
			uiIn_ACCELPercent:=2 , 
			uiIn_DECELPercent:=10 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE AND NOT arstGV_Cell1_LoadAxisXStop, 
			bIn_CMD_INIT:= FALSE);  		 
     IF Delay_SensorCheck.Q THEN 
		 Step :=200;	
	 ELSIF  AxisX_ExecuteEnd AND stGV_SYS_ELEMENTS.arstELEMENT[idxLoad_AxisX].stFeedBack.stSTATE.bIN_POSITION AND Delay.Q THEN // Wait Moved
	     wINOUT_DIAGNOSE_Seq.4 := TRUE;	// Alignement Sensor Shoul Not Be All On( Cable Label:2045B10(S18)+Cable Label:2046B10(S19))
         Step :=999; 		 
	 END_IF	
  200 : // Reset Timer
	     Delay.IN := FALSE; 
		 arstGV_Cell1_LoadAxisXStop := TRUE;  
	 IF NOT Delay.Q AND NOT PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.IsMoving  THEN 	
          Step :=205; 	 
	 END_IF	
  205 : // Reset ControlRelease 
            Delay.IN := TRUE;	   
            Delay.PT := T#20MS;  
    	   arstGV_Cell1_LoadAxisXStop := FALSE;
		   arstGV_Cell1_LoadAxisYStop := FALSE;	
	 IF Delay.Q AND PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.Ready AND PRG_Cell1_Hardwarelayer.AI_LoadAxisY.FROM_AXIS.Ready THEN 
          Step :=210; 	 
	 END_IF	
  210 : // Reset Timer
	     Delay.IN := FALSE; 
 	 IF  NOT Delay.Q THEN 
          Step :=220; 	 
	 END_IF		 
  220 : // 按速度比例执行 轴 XY 移动至 S20 检测成功
       IF  tAngle < -0.5 THEN  //顺时针 Vy+ Vx+
	     arstGV_Cell1_LoadAxisXOffset.rX   := 100.0;			
		 arstGV_Cell1_LoadAxisYOffset.rX   := 100.0;			 
	 ELSIF  tAngle >0.5 THEN  //逆时针 Vy+ Vx-
		 arstGV_Cell1_LoadAxisXOffset.rX   := -100.0;	
		 arstGV_Cell1_LoadAxisYOffset.rX   := 100.0;
	 ELSIF  tAngle >=-0.5 AND  tAngle <=0.5 THEN 
		 arstGV_Cell1_LoadAxisXOffset.rX   := 0;	
		 arstGV_Cell1_LoadAxisYOffset.rX   := 100.0;			 
	 END_IF	
           Delay.IN := TRUE;	   
           Delay.PT := T#30MS;  				
		   tAxisXVel := ABS(tAngle_Radian) * 10;	
  		 AxisX_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisX , 
			rIn_Position:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=tAxisXVel , 
			uiIn_ACCELPercent:=1, 
			uiIn_DECELPercent:=1, 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE AND NOT arstGV_Cell1_LoadAxisXStop , 
			bIn_CMD_INIT:= FALSE); 		 
  		 AxisY_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisY , 
			rIn_Position:= arstGV_Cell1_LoadAxisY_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisY_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=10.0 , 
			uiIn_ACCELPercent:=1 , 
			uiIn_DECELPercent:=1 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=   stVar_SEQ.bRELEASE AND NOT arstGV_Cell1_LoadAxisYStop , 
			bIn_CMD_INIT:= FALSE);   					
		 IF  AxisX_ExecuteEnd AND AxisY_ExecuteEnd AND Delay.Q THEN // Wait Moved
			 wINOUT_DIAGNOSE_Seq.5 := TRUE;		// Alignement Sensor Shoul Be On( Cable Label:2047B10(S20))	 
			 Step :=999;
		 ELSIF bIN_AligneY_Sensor THEN 
			 Step :=230; 		 
		 END_IF	
   230 :	
	     arstGV_Cell1_LoadAxisXStop := TRUE;
	     arstGV_Cell1_LoadAxisYStop := TRUE;
	     Delay.IN := FALSE;
		 tAlignementEndAxisXPos:=0.0;	 
    IF   NOT Delay.Q AND NOT PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.IsMoving AND NOT PRG_Cell1_Hardwarelayer.AI_LoadAxisY.FROM_AXIS.IsMoving AND tAlignementEndAxisXPos = 0.0 THEN 		 
		 Step :=240; 	 
	 END_IF		 
   240 ://记录当前AxisX位置数据值用于挂钩
   	     tAlignementEndAxisXPos:=PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.ACT_POS;	 
    IF   tAlignementEndAxisXPos <> 0.0  THEN 		 
		 Step :=250; 	 
	 END_IF	
  250 : // Reset Timer
	     Delay.IN := FALSE; 
		 arstGV_Cell1_LoadAxisXStop := FALSE;
		 arstGV_Cell1_LoadAxisYStop := FALSE;		  
	 IF NOT Delay.Q AND PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.Ready AND PRG_Cell1_Hardwarelayer.AI_LoadAxisY.FROM_AXIS.Ready THEN 
          Step :=260; 	 
	 END_IF		 
  260 : // 执行轴 移动到抓取位 (Z)
             Delay.IN := TRUE;
			 Delay.PT := T#20MS;
             arstGV_Cell1_LoadAxisZOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.NoOffset].rX;
  		 AxisZ_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisZ , 
			rIn_Position:= arstGV_Cell1_LoadAxisZ_Pos[Pick_No+1].rX, 
			sIn_PosComment:= arstGV_Cell1_LoadAxisZ_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=cSlow ,
			uiIn_ACCELPercent:=2 , 
			uiIn_DECELPercent:=10 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:= stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE); 	
	 IF  AxisZ_ExecuteEnd AND Delay.Q THEN // Wait Moved		 
          Step :=270; 
	 END_IF	
  270 : // Reset Timer
	     Delay.IN := FALSE; 		  
	 IF NOT Delay.Q AND PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.StandStill THEN 
          Step :=280; 	 
	 END_IF			 
   280 ://  AxisX 移动至提起料箱位 (+15.0mm)
             Delay.IN := TRUE;
			 Delay.PT := T#1S;  	 
		     arstGV_Cell1_LoadAxisXOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.KltBox_HookEntry].rX;	 
  		 AxisX_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:= idxLoad_AxisX , 
			rIn_Position:= tAlignementEndAxisXPos,  //当前位置
			sIn_PosComment:= arstGV_Cell1_LoadAxisX_Pos[Pick_No+1].sComment, 
			rIn_Speed_In_Units:=1.0 , 
			uiIn_ACCELPercent:=2 , 
			uiIn_DECELPercent:=10 , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=  stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE);  		 
	 IF  AxisX_ExecuteEnd AND Delay.Q AND PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.StandStill THEN // Wait Moved	
          Step :=290; 
	 END_IF	 
  290 : // Reset Timer
	     Delay.IN := FALSE; 		  
	 IF NOT Delay.Q THEN 
          Step :=300; 	 
	 END_IF		 
  300 : // 执行轴 移动到 待机位 (Z)
            Delay.IN := TRUE;
			Delay.PT := T#20MS;  
            arstGV_Cell1_LoadAxisZOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.NoOffset].rX;
       AxisZ_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:=  idxLoad_AxisZ, 
			rIn_Position:= stAxisPosZ[E_AxisPositions_Cell1.Standby].rX, 
			sIn_PosComment:= stAxisPosZ[E_AxisPositions_Cell1.Standby].sComment, 
			rIn_Speed_In_Units:=50.0, 
			uiIn_ACCELPercent:=cACCEL , 
			uiIn_DECELPercent:=cDECL , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=  stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE); 			
	 IF  AxisZ_ExecuteEnd AND Delay.Q THEN // Wait Moved	
          Step :=305; 
	 END_IF	
  305 : // Reset Timer
	     Delay.IN := FALSE; 		  
	 IF NOT Delay.Q THEN 
          Step :=306; 	 
	 END_IF		 
  306 : // 检测料筐存在于挂钩
		Delay.IN := TRUE;
		Delay.PT := T#0.5S; 		  
	 IF  Delay.Q AND bIN_KltInCraneGripper THEN 
          Step :=310; 
	 ELSIF  Delay.Q AND NOT bIN_KltInCraneGripper THEN 
		   wINOUT_DIAGNOSE_Seq.6 := TRUE;	// Klt Check Sensor Should Be No (Cable Label:2048B10(S85))	
	 END_IF		 
  310 : 
		 Pick_No:= Pick_No-1; // 更新下一次抓取数
          Step :=315; 	 
  315 : // Reset Timer
	     Delay.IN := FALSE; 
	 IF NOT Delay.Q THEN 
          Step :=320; 	 
	 END_IF			 
  320 : // 执行轴 移动到 待机位 (Y)
            Delay.IN := TRUE;
			Delay.PT := T#20MS;  
            arstGV_Cell1_LoadAxisYOffset.rX   :=stGV_Cell1_AxisOffset[E_AxisPosData_Offset.NoOffset].rX;
       AxisY_ExecuteEnd:=F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1(
			iIn_idxElement:=  idxLoad_AxisY, 
			rIn_Position:= stAxisPosY[E_AxisPositions_Cell1.Standby].rX, 
			sIn_PosComment:= stAxisPosY[E_AxisPositions_Cell1.Standby].sComment, 
			rIn_Speed_In_Units:=50.0 , 
			uiIn_ACCELPercent:=cACCEL , 
			uiIn_DECELPercent:=cDECL , 
			rIN_Precision:= cPrecisionNormal, 
			bIn_CMD_POS:=  stVar_SEQ.bRELEASE , 
			bIn_CMD_INIT:= FALSE); 			
	 IF  AxisY_ExecuteEnd AND Delay.Q THEN // Wait Moved	
          Step :=400; 
	 END_IF	
   400 :	
		 arstGV_Cell1_LoadAxisXOffset.rX:=0.0;
		 arstGV_Cell1_LoadAxisYOffset.rX:=0.0;
		 arstGV_Cell1_LoadAxisZOffset.rX:=0.0;
		 arstGV_Cell1_LoadAxisROffset.rX:=0.0; 
		 arstGV_Cell1_LoadAxisXStop := FALSE;
	     arstGV_Cell1_LoadAxisYStop := FALSE;	
	     Delay.IN := FALSE; 		
	     stVar_SEQ.bTOK := TRUE;
    IF NOT Delay.Q AND stVar_SEQ.bTOK THEN 		 
		 Step :=0; 	 
	 END_IF			 
END_CASE

IF 	Step =105  THEN
	 IF  bIN_AligneX_Sensor1  AND NOT  tAligneX_Sensor1_CheckOK THEN 
		  tAligneX_Sensor1_CheckOK:=TRUE;
	      tCheckPos1 := PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.ACT_POS;
	 ELSIF  bIN_AligneX_Sensor2  AND NOT tAligneX_Sensor2_CheckOK THEN 
		  tAligneX_Sensor2_CheckOK:=TRUE;		 
	      tCheckPos2 := PRG_Cell1_Hardwarelayer.AI_LoadAxisX.FROM_AXIS.ACT_POS;
	 END_IF	
 END_IF	

三、对以上源代码的分析

      这是一段工业自动化中用于料筐(KLT Box)自动对中与抓取的控制程序,主要实现对料筐位置的精确检测、角度校准和抓取操作。以下是详细分析:

3.1 核心功能解析

1. 整体流程

初始化(Step 10-25):清除缓存数据,将轴移动到待机位和检测位。
位置检测(Step 30-55):通过传感器(bIN_AligneX_Sensor1/bIN_AligneX_Sensor2)检测料筐位置,判断是否存在。
角度校准(Step 100-135):计算料筐偏移角度,旋转轴(R 轴)进行角度校准。
精确定位(Step 200-240):根据校准结果,调整 X/Y 轴位置,使抓取机构对准料筐。
抓取操作(Step 250-320):Z 轴下降到抓取位,X 轴移动到提起位置,Z 轴上升,完成抓取。
状态检查(Step 306-400):确认料筐已被抓取,更新计数,返回待机位。

2. 关键技术细节

传感器逻辑

使用两个对齐传感器(S18/S19)检测料筐 X 方向位置。
通过延迟检测(Delay_SensorCheck)确保传感器信号稳定。
使用超时机制(Delay_SensorCheckAlarm)处理传感器异常。

角度计算

通过两次位置检测(tCheckPos1/tCheckPos2)计算角度偏差:

plaintext

tAngle_Radian := ATAN((tCheckPos2 - tCheckPos1)/300.0);
tAngle := tAngle_Radian * 180.0 / 3.141592654;

根据角度调整 R 轴旋转,补偿料筐偏移。

轴控制

使用 F_SEQ_X_UNI_AXES_ABS_POS_Precision_V1_1 功能块实现轴的绝对位置控制。
支持多轴联动(如 X/Y 轴同步移动),速度和加速度可配置。

3.2  局限性分析

1. 硬编码参数依赖

固定偏移量:角度补偿值(如 0.2)、移动距离(如 100.0mm)为硬编码,无法自适应不同规格料筐。
固定传感器位置:假设传感器位置与料筐尺寸完全匹配,若实际布局变化,需手动修改代码。

2. 错误处理能力有限

单一错误码:仅通过 wINOUT_DIAGNOSE_Seq 记录错误类型,缺乏详细的错误上下文(如具体轴位置、传感器状态)。
恢复机制不足:遇到错误(如传感器超时)后直接跳转到错误处理(Step 999),未尝试自动恢复或重试。

3. 传感器可靠性风险

单点故障:依赖单个传感器判断料筐存在性(bIN_KltInCraneGripper),若传感器失效,可能导致误操作。
信号干扰:未对传感器信号进行滤波或冗余校验,可能受环境干扰影响。

4. 性能与效率问题

慢速运动:部分操作(如校准阶段)速度极低(如 1.0 units/s),影响整体节拍。
重复检测:每次抓取前需重新校准,即使料筐位置相对固定。

5. 缺乏柔性适配

单一料筐类型:仅支持一种规格料筐,无法自动识别或切换不同尺寸的料筐。
固定路径规划:轴运动轨迹为预设路径,无法动态避障或适应布局变化。

3.3 改进建议

参数化设计

将关键参数(如偏移量、速度)存储在配置文件中,支持动态调整。
添加料筐类型选择功能,根据不同产品切换参数。

增强错误处理

实现多级错误恢复机制(如重试、降级操作)。
记录详细错误日志(时间、轴位置、传感器状态),便于故障排查。

传感器优化

增加传感器冗余设计(如多传感器交叉验证)。
添加信号滤波和异常检测算法,提高可靠性。

效率提升

引入位置记忆功能,对重复位置减少校准步骤。
优化运动规划,并行执行多轴动作(如 X/Y 轴同步移动)。

智能化升级

集成机器视觉系统,实时检测料筐位置和姿态,减少对固定传感器的依赖。
实现自适应控制,根据历史数据优化校准参数。

3.4 总结

该程序实现了料筐自动对中与抓取的基本功能,但受限于硬编码参数、简单错误处理和固定流程,在柔性生产、故障恢复和效率方面存在提升空间。通过参数化、智能化和冗余设计,可显著增强系统的适应性和可靠性。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容