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

目录
一、以下是编程的核心要领和关键点:
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 语句)实现流程控制,确保步骤有序执行。
数据结构规划
定义轴位置、传感器状态、校准参数等数据类型。
使用全局变量或结构体存储关键数据(如 tCheckPos1、tAlignementEndAxisXPos)。
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_MoveAbsolute、F_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/Neg、SwLimitSwitchPos/Neg)防止轴超限。
在轴运动前检查驱动器状态(如 CommunicationReady、PowerOn)。
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 总结
该程序实现了料筐自动对中与抓取的基本功能,但受限于硬编码参数、简单错误处理和固定流程,在柔性生产、故障恢复和效率方面存在提升空间。通过参数化、智能化和冗余设计,可显著增强系统的适应性和可靠性。




















暂无评论内容