How to call by variable, and how not to.
Here a programmer hard coded the routine name to a string to be used in a Call by variable. It pretty much defeats the purpose of using a Call by Variable and creates extra steps as well. There are two ways to use a call by variable: 1. %MyRoutine%; where the string between the percent signs is the name of the routine to run. 2. CallByVar "MainTyp", nProg; The number value is automatically converted to a string and concatenated onto the string name of the routine.
!**************** STRING ****************
!
! "stMainTyp1" Call for main routine, for engine type 1 (DO NOT EDIT).
CONST string stMainTyp1:="MainTyp1";
! "stMainTyp2" Call for main routine, for engine type 2 (DO NOT EDIT).
CONST string stMainTyp2:="MainTyp2";
! "stMainTyp3" Call for main routine, for engine type 3 (DO NOT EDIT).
CONST string stMainTyp3:="MainTyp3";
! "stMainTyp4" Call for main routine, for engine type 4 (DO NOT EDIT).
CONST string stMainTyp4:="MainTyp4";
TEST nProg
CASE 1:
%stMainTyp1%;
CASE 2:
%stMainTyp2%;
CASE 3:
%stMainTyp3%;
CASE 4:
%stMainTyp4%;
ENDTEST
So one could skip the string assignment and do things a couple different ways. One way to do it would be like this:
TEST nProg
CASE 1:
CallByVar "MainTyp", nProg;
CASE 2:
CallByVar "MainTyp", nProg;
CASE 3:
CallByVar "MainTyp", nProg;
CASE 4:
CallByVar "MainTyp", nProg;
ENDTEST
Or even more compact:
TEST nProg
CASE 1, 2, 3, 4:
CallByVar "MainTyp", nProg;
ENDTEST
And even like this:
TEST nProg
CASE 1, 2, 3, 4:
%"MainTyp" + NumToStr(nProg,0)%;
ENDTEST
How to loop your main program, run continuously
So we are done beating that horse now. This is another example of something that makes me go "What?" This is a Main routine which has a label, begin. At the end, GOTO begin. There are only comment above Begin, no code which you might want to run only once after a PPtoMain. If the goal is to keep the program running continuously, rather than single, then the run mode for the controller should be set to continuous. Simple, done, problem solved. I have also seen Main routines with a RETURN at the end. Um, this is the MAIN routine, where do you expect it will RETURN to?
!----- Main Routine -----
PROC main()
!******************************
!
! HOOD & LIFTGATE CELL
!******************************
! MAIN PROGRAM
!******************************
begin:
!--- Robot Initial Condition --
!Move To Home
move_home;
!Initialize I/O
home_IO;
!
stop_timer 1;
!
TPErase;
TPWrite "Waiting for Cycle Start";
WaitDI cycle_start,1;
TPErase;
!
start_timer 1;
!
!-- Get Style Number From PLC -
style_no:=program_select;
!
!--- Style Selection ---
TEST style_no
CASE 1:
!Hood
style1;
CASE 2:
!Liftgate
style2;
CASE 8:
!Service
style8;
CASE 11:
!Change Tool to Hood
style11;
CASE 12:
!Change Tool to Liftgate
style12;
DEFAULT:
WHILE TRUE DO
ENDWHILE
ENDTEST
!
!--- Robot Initial Condition --
!Move To Home
move_home;
!Initialize I/O
home_IO;
!
!Clear Style Select Register
style_no:=0;
!
GOTO begin;
ENDPROC
The other way one could stay in an infinite loop is to write it like this:
PROC Main()
WHILE TRUE DO
Put all the stuff the robot should do in a cycle here. It will repeat forever unless there is a PPtoMain, from the pendant or PLC, an EXITCYCLE instruction or EXIT.
ENDWHILE
ENDPROC
Use built in functions whenever possible
The following is just part of a routine where someone demonstrates their math knowledge. I have seen it and variations of it used here and there. While I give an "A" for the math grade it is more like a "C" for the Rapid programming.
VAR num nDistance:=0;
VAR num xDistance:=0;
VAR num yDistance:=0;
VAR num zDistance:=0;
VAR num i:=0;
xDistance:=(pCurPos.trans.x-pPosition.trans.x)*(pCurPos.trans.x-pPosition.trans.x);
yDistance:=(pCurPos.trans.y-pPosition.trans.y)*(pCurPos.trans.y-pPosition.trans.y);
zDistance:=(pCurPos.trans.z-pPosition.trans.z)*(pCurPos.trans.z-pPosition.trans.z);
nDistance:=xDistance+yDistance+zDistance;
nDistance:=Sqrt(nDistance);
Here is another which was written as a function:
FUNC num RobtToRobtDist(
robtarget PointA,
robtarget PointB)
! This procedure calculates the distance between two robtargets.
VAR num nDistance:=0;
!
nDistance:=(PointA.trans.x-PointB.trans.x)*(PointA.trans.x-PointB.trans.x)+(PointA.trans.y-PointB.trans.y)*(PointA.trans.y-PointB.trans.y)+(PointA.trans.z-PointB.trans.z)*(PointA.trans.z-PointB.trans.z);
RETURN (Sqrt(nDistance));
ENDFUNC
I just use the built in Rapid function:
nDistance := Dist(p10.trans,p20.trans);
But how do I know if there is a function already available that does what I need? Read the Manual.
Increment and Decrement
When one needs to count up or count down you could do it like the following:
VAR num nMyCounter;
nMyCounter:=10;
WHILE nMyCounter > 0 DO
Blah, blah, stuff here;
nMyCounter := nMyCounter - 1;
ENDWHILE
Please don't do that unless you need to go up or down for some reason by 2, 5, 10, whatever. Rapid has two instructions to count up or down by one - INCR and DECR, use them.
FOR, ENDFOR
There have been many times when I see code like this:
VAR num i;
FOR i FROM 1 TO 10 DO
Blah, blah, stuff
ENDFOR
The value of i is initialized when the FOR is executed. You could declare VAR num i:=100, but if the FROM says 1 TO 10 it will be 1 when the execution of FOR begins. Leave out the declaration of i (or j or whatever you want it to be) because it is unnecessary. The value if i is only visible within the scope of the FOR, ENDFOR. If, for some reason, you need to examine the value, it must be nested within that loop.
Learn to use Error handlers and Backwards handlers
Instead of putting cheesy GOTO's in your program for when a gripper is not closed, RAISE an Error and have an Error handler. There are a lot of options to Retry, Raise Trynext and such. A lesser known and even less used is the Backwards handler. You could reset a bit you had set, or vice versa. Even just putting a simple Return statement makes stepping backwards through your programs more user friendly because it will allow the user to continue stepping backwards past the Proc call.
UNDO Handler
This one is a cool feature of Rapid too. Take, for example, this scenario. Someone hits PPToMain, your UNDO handler sets or resets IO that your routine has set. Put it in your UNDO handler to restore IO or variables to the state that you need them to be if your routine is terminated early.
Comments 1