Advertising

Rapid 201: Set yourself ahead of the crowd.

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

  • I never worked with ABB, I did a lot of work with Fanuc and microcontrolers and general PC programming. I have few objections with a great blog post that shows some of the functionality


    I'd argue that the person in the first example didn't use Call by variable in any sense of the function, just a normal call to function. It's actualy the same as the third example, use functions that exist, don't make your own.

    It's a good advice, but very often it's not easy to find all the useful functions, especialy if you're not sure they exist. (experience not from ABB and Rapid, but from general programing with switching of languages all the time). So saying basically "this person is a horrible programmer because he doesn't know all the useful functions" seems a bit rude, especially if the program works properly and does exactly what it needs to.

    Advice in form "these are cool functions that people don't use enough" would be much better and much less hostile.


    For second example, "while true do" version makes it more complicated to jump to the beginning of program from other points. And if you want to do something only on first run of the program you don't want it to run in continuos mode. Of course this program would be better in continues without that part, but do you really want to write your programs in a way that you have to check for each in which mode it should be ran?



    What's the point of using increment and decrement except to lose few characters? It seems to do exactly the same as the one line command that does it, but it's specific to that programing language, and less clear without a programming manual by your side.
    And this way if you need to go by 2 you can do it very simple, why would you want to do two different functions for the exact same thing, just different parameters?



    FOR example explains the difference between Rapid and 90% of other programing languages, but it does it in an attacking way and doesn't show the full difference between common FOR and the one specific for Rapid (it doesn't mention that you can't change "i" from inside the function)



    This seems more like an agressive code review than a general "tips and tricks" post. Information in it is useful, even though I'd disregard some of it as personal choice, but I don't like the presentation enough to write a comment on it :)