Hi Fabrice,
I have done this ones before. Read and see if you understand the example.
the purpose was to moved all the APPROACH points to the side and added another TARGET point.
I modified the code in the last loop in Operate:
WHILE PmGetTgtAction(WorkArea, Tgt.TargetHandle,Act) DO
to call a new procedure ModAction.
…
PmGetOperation WorkArea, Op;
WHILE PmGetTarget(WorkAreaOpHandle:=Op.OpHandle,Tgt) DO
WHILE PmGetTgtAction(WorkArea, Tgt.TargetHandle,Act) DO
ModAction WorkArea, Tgt, Act, FirstTgtInOp;
ENDWHILE
ENDWHILE
MultiOperation:=FALSE;
ERROR
…
In ModAction I checked if I was operating on an infeeder. If so I made the additional motion.
!***********************************************************
!
! Procedure ModAction
!
! This routine executes modifies one action and orders
! the move.
! Before moving towards every first target in the
! operation, the robot will go to a intermediate position.
!
! Arguments:
! IN:
! pm_wadescr WorkArea
! pm_targetdata Tgt
! pm_actiondata Act
! INOUT:
! bool FirstTgtInOp
!
!***********************************************************
PROC ModAction(VAR pm_wadescr WorkArea, VAR pm_targetdata Tgt, VAR pm_actiondata Act, INOUT bool FirstTgtInOp)
VAR string sWAName;
VAR num nWANameFound;
VAR pos RelToolOffset:=[0,0,0];
VAR stoppointdata tempStopPoint;
VAR pm_movetype tempMoveType;
VAR robtarget tempRobTgt;
sWAName := PmGetWaName (WorkArea);
nWANameFound := StrMatch(sWAName, 1, “Infeed”);
!Stop;
TempTool:=Tgt.TargetTool;
ActTgt:=Act.RobTgt;
TGTTgt:=Tgt.robtgtpoint;
TPWrite "Tgt.TargetTool X"Num:=TempTool.tframe.trans.x;
TPWrite "Tgt.TargetTool Y"Num:=TempTool.tframe.trans.y;
TPWrite "Tgt.TargetTool Z"Num:=TempTool.tframe.trans.z;
TPWrite "Tgt.TargetTool q1"Num:=TempTool.tframe.rot.q1;
TPWrite "Tgt.TargetTool q2"Num:=TempTool.tframe.rot.q2;
TPWrite "Tgt.TargetTool q3"Num:=TempTool.tframe.rot.q3;
TPWrite "Tgt.TargetTool q4"Num:=TempTool.tframe.rot.q4;
TPWrite "Act.RobTgt X"Num:=ActTgt.trans.x;
TPWrite "Act.RobTgt y"Num:=ActTgt.trans.y;
TPWrite "Act.RobTgt z"Num:=ActTgt.trans.z;
TPWrite "Tgt.robtgtpoint x"Num:=TGTTgt.trans.x;
TPWrite "Tgt.robtgtpoint y"Num:=TGTTgt.trans.y;
TPWrite "Tgt.robtgtpoint z"Num:=TGTTgt.trans.z;
IF nWANameFound = 1 THEN
IF Act.Type = PM_APPROACH_POS THEN
RelToolOffset.x:=nXOffSet;
ELSEIF Act.Type = PM_TARGET_POS THEN
tempStopPoint.Type:=Tgt.StopPointData.Type;
tempMoveType:=Act.Move;
Tgt.StopPointData.Type:=0;
Act.Move:=PM_MOVE_LIN;
tempRobTgt:=Act.RobTgt;
RelToolOffset.x:=nXOffSet;
! Order an extra position with a horizontal offset
MoveAction WorkArea, Tgt, Act, RelToolOffset, FirstTgtInOp MoveLOnly;
! Copy back the saved data.
Tgt.StopPointData.Type:=tempStopPoint.Type;
Act.Move:=tempMoveType;
Act.RobTgt:=tempRobTgt;
RelToolOffset:=[0,0,0];
ENDIF
ENDIF
MoveAction WorkArea, Tgt, Act, RelToolOffset, FirstTgtInOp;
ERROR
TEST ERRNO
CASE PM_ERR_PALLET_REDUCED:
RAISE;
CASE PM_ERR_PALLET_EMPTY:
RAISE;
ENDTEST
ENDPROC
MoveAction then took care of the intermediate point:
!***********************************************************
!
! Procedure MoveAction
!
! This routine executes modifies one action and orders
! the move.
! Before moving towards every first target in the
! operation, the robot will go to a intermediate position.
!
! Arguments:
! IN:
! pm_wadescr WorkArea
! pm_targetdata Tgt
! pm_actiondata Act
! pos MoveRelTool
! INOUT:
! bool FirstTgtInOp
!
!***********************************************************
PROC MoveAction(VAR pm_wadescr WorkArea, VAR pm_targetdata Tgt, VAR pm_actiondata Act, VAR pos MoveRelTool, INOUT bool FirstTgtInOp, switch MoveLOnly)
PmCalcArmConf Act.RobTgt,Tgt.TargetTool,Tgt.TargetWobjcf6MaxAngle:=MaxToolAngleMinAngle:=MinToolAngle;
IF FirstTgtInOp AND (NOT MultiOperation) THEN
MoveInterMid Tgt,Act,SafetyHeightMaxToolAngle:=MaxToolAngleMinToolAngle:=MinToolAngle;
FirstTgtInOp:=FALSE;
ENDIF
MyDoAction WorkArea,Tgt,Act MoveLOnly?MoveLOnly;
SetLastPos Tgt,Act;
ERROR
TEST ERRNO
CASE ERR_WAIT_MAXTIME:
SetGO goFaultNo, 6;
Exit;
CASE PM_ERR_PALLET_REDUCED:
RAISE;
CASE PM_ERR_PALLET_EMPTY:
RAISE;
ENDTEST
ENDPROC
Then I had to make a copy of the procedire PmDoAction from the built-in pre-loaded module pmrcSys.sys that is only viewable in RobotStudio.
Paste it into pmrcUser.sys with a new name and add the switch switch MoveLOnly.
!***********************************************************
!
! Procedure MyDoAction
!
! This routine setup event and all modal data. The move
! is ordered when all modal data are setup.
!
!***********************************************************
PROC MyDoAction(VAR pm_wadescr WorkArea, VAR pm_targetdata Tgt, VAR pm_actiondata Act, switch MoveLOnly)
VAR pm_eventdata Event;
VAR signaldo doSignal;
VAR signalgo goSignal;
VAR num NumOfTriggEvents:=0;
VAR num ArrSize:=0;
VAR triggdata TriggArr{6};
VAR stoppointdata curr_StopPoint;
VAR num TriggEventTime;
VAR string signalname;
ArrSize := Dim(TriggArr,1);
IF NOT Present(MoveLOnly) THEN
WHILE PmGetEvent(WorkArea, Tgt.TargetHandle, Act.ActionHandle, Event) AND NumOfTriggEvents < ArrSize DO
TEST Event.Type
CASE PM_EVENT_PROC:
Incr NumOfTriggEvents;
TriggEquip TriggArr{NumOfTriggEvents}, Event.Dist, Event.Time, ProcID:=Event.ProcId, Event.Value;
CASE PM_EVENT_DO:
Incr NumOfTriggEvents;
GetDataVal Event.SignalName,doSignal;
IF Act.type = PM_TARGET_POS AND Tgt.StopPointData.type = 2 THEN
TriggEventTime := Event.time - Tgt.stopPointData.stoptime / 2;
IF TriggEventTime >= 0 THEN
TriggIO TriggArr{NumOfTriggEvents}, TriggEventTime, Time, DOp:=doSignal, Event.Value;
ELSE
TriggIO TriggArr{NumOfTriggEvents}, 0, Time, DOp:=doSignal, Event.Value DODelay:=-TriggEventTime;
ENDIF
ELSE
TriggEquip TriggArr{NumOfTriggEvents}, Event.Dist, Event.Time, DOp:=doSignal, Event.Value;
ENDIF
CASE PM_EVENT_GO:
Incr NumOfTriggEvents;
GetDataVal Event.SignalName,goSignal;
IF Act.type = PM_TARGET_POS AND Tgt.StopPointData.type = 2 THEN
TriggEventTime := Event.time - Tgt.stopPointData.stoptime / 2;
IF TriggEventTime >= 0 THEN
TriggIO TriggArr{NumOfTriggEvents}, TriggEventTime, Time, GOp:=goSignal, Event.Value;
ELSE
TriggIO TriggArr{NumOfTriggEvents}, 0, Time, GOp:=goSignal, Event.Value DODelay:=-TriggEventTime;
ENDIF
ELSE
TriggEquip TriggArr{NumOfTriggEvents}, Event.Dist, Event.Time, GOp:=goSignal, Event.Value;
ENDIF
CASE PM_EVENT_WAIT_DI:
Incr NumOfTriggEvents;
IF pm_LastUsedIndex = pm_ToolEventsArrSize THEN
pm_LastUsedIndex:=1;
ELSE
Incr pm_LastUsedIndex;
ENDIF
GetDataVal Event.SignalName,pm_diSignals{pm_LastUsedIndex};
pm_SignalNames{pm_LastUsedIndex}:=Event.SignalName;
pm_diValues{pm_LastUsedIndex}:=Event.Value;
IDelete pm_IntNos{pm_LastUsedIndex};
CONNECT pm_IntNos{pm_LastUsedIndex} WITH TrapDIToolEvents;
TriggCheckIO TriggArr{NumOfTriggEvents},0,pm_diSignals{pm_LastUsedIndex},EQ,pm_diValues{pm_LastUsedIndex}StopMove,pm_IntNos{pm_LastUsedIndex};
CASE PM_EVENT_WAIT_GI:
Incr NumOfTriggEvents;
IF pm_LastUsedIndex = pm_ToolEventsArrSize THEN
pm_LastUsedIndex:=1;
ELSE
Incr pm_LastUsedIndex;
ENDIF
GetDataVal Event.SignalName,pm_giSignals{pm_LastUsedIndex};
pm_SignalNames{pm_LastUsedIndex}:=Event.SignalName;
pm_giValues{pm_LastUsedIndex}:=Event.Value;
IDelete pm_IntNos{pm_LastUsedIndex};
CONNECT pm_IntNos{pm_LastUsedIndex} WITH TrapGIToolEvents;
TriggCheckIO TriggArr{NumOfTriggEvents},0,pm_giSignals{pm_LastUsedIndex},EQ,pm_giValues{pm_LastUsedIndex}StopMove,pm_IntNos{pm_LastUsedIndex};
DEFAULT:
PmErrorLog 2356, ERRSTR_TASK, ValToStr(Event.Type), ERRSTR_CONTEXT, ERRSTR_UNUSED, ERRSTR_UNUSED;
ENDTEST
ENDWHILE
ENDIF
TEST Act.Type
CASE PM_APPROACH_POS:
curr_Load := Tgt.AppProdsLoad;
CASE PM_TARGET_POS:
curr_Load := Tgt.AppProdsLoad;
curr_StopPoint:=Tgt.StopPointData;
CASE PM_DEPART_POS:
curr_Load := Tgt.DepProdsLoad;
DEFAULT:
PmErrorLog 2357, ERRSTR_TASK, ValToStr(Act.Type), ERRSTR_CONTEXT, ERRSTR_UNUSED, ERRSTR_UNUSED;
ENDTEST
curr_WObj := Tgt.TargetWobj;
curr_Tool := Tgt.TargetTool;
PathAccLim Act.Accel.AccLimAccMax:=Act.Accel.AccMax, Act.Accel.DecelLimDecelMax:=Act.Accel.DecelMax;
AccSet Act.Accel.acc, Act.Accel.Ramp;
GripLoad curr_Load;
IF Act.ArmConfMon = TRUE THEN
ConfLOn;
ConfJOn;
ELSE
ConfLOff;
ConfJOff;
ENDIF
IF Act.SingAreaType = PM_SING_AREA_WRI THEN
SingAreaWrist;
ELSE
SingAreaOff;
ENDIF
TEST NumOfTriggEvents
CASE 0:
IF Act.Move = PM_SEARCH_LIN THEN
PmDoSearch WorkArea,Tgt.TargetHandle,Act.RobTgt,Act.Speed,Act.Search,curr_Tool,curr_WObj;
PmAckTarget WorkArea,Tgt,PM_ACK;
ELSE
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.Speed,Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
ENDIF
CASE 1:
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.SpeedT1:=TriggArr{1},Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
CASE 2:
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.SpeedT1:=TriggArr{1}T2:=TriggArr{2},Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
CASE 3:
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.SpeedT1:=TriggArr{1}T2:=TriggArr{2}T3:=TriggArr{3},Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
CASE 4:
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.SpeedT1:=TriggArr{1}T2:=TriggArr{2}T3:=TriggArr{3}T4:=TriggArr{4},Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
CASE 5:
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.SpeedT1:=TriggArr{1}T2:=TriggArr{2}T3:=TriggArr{3}T4:=TriggArr{4}T5:=TriggArr{5},Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
CASE 6:
PmDoMove1 Act.Move,Act.UseConc,Act.RobTgt,Act.SpeedT1:=TriggArr{1}T2:=TriggArr{2}T3:=TriggArr{3}T4:=TriggArr{4}T5:=TriggArr{5}T6:=TriggArr{6},Act.Zone,curr_StopPoint,curr_Tool,curr_WObj;
DEFAULT:
PmErrorLog 2355, ERRSTR_TASK, ValToStr(NumOfTriggEvents), ERRSTR_CONTEXT, ERRSTR_UNUSED, ERRSTR_UNUSED;
ENDTEST
ERROR
TEST ERRNO
CASE ERR_SYM_ACCESS:
IF Event.SignalName = “” THEN
signalname := “”;
ELSE
signalname := Event.SignalName;
ENDIF
PmErrorLog 2354, ERRSTR_TASK, signalname, ERRSTR_CONTEXT, ERRSTR_UNUSED, ERRSTR_UNUSEDErrorHandler:=TRUE;
RaiseToUser BreakOff;
CASE PM_ERR_PALLET_REDUCED:
PmAckTarget WorkArea,Tgt,PM_ACK;
RAISE;
CASE PM_ERR_PALLET_EMPTY:
PmAckTarget WorkArea,Tgt,PM_ACK;
RAISE;
DEFAULT:
RAISE;
ENDTEST
ENDPROC
That’s it.
Good luck!
/Mats