To make the most of the limited program sizes in the robot controller it is advantageous to use subroutines when possible. In short, subroutines are blocks of code that can be executed by a single line of code (e.g. SUB 31). Subroutines can have as much code as needed and can call other subroutines (known as nesting) up to 16 layers deep.
Subroutines can be very simple such as the following example to open a gripper:
Code:
SUBROUTINE 32
0010 VON 6
0020 VOFF 5
0030 TIM 50
0040 END
Or they can be as complicated as needed. There are no parameters that can be passed into the subroutine from the subroutine call, but the subroutine can read and write global variables just like the main program. For example the main program might write the value 10.0 to Floating Point variable 1
and the subroutine might copy that to Floating Point variable 2
Code:
SUBROUTINE 33
0010 S F0002=F0001
0020 END
The power of this global variable access comes when you get into
indirect addressing. Indirect addressing allows you to access the data in a variable based on the value of a different variable. In the simple example below, The value from Floating Point variable 2 is copied into Floating Point variable 1, and then later Floating Point variable 3 is copied into Floating Point variable 1, but they use the same subroutine
Code:
PROGRAM 1
0010 S I0001=2
0020 SUB 1
0030 S I0001=3
0040 SUB 1
0050 END
SUBROUTINE 1
0010 S F0001=I0001.F
0020 END
In the example above, the integer variable "I0001" contains the value of index of the floating point array to be copied. In a traditional programming sense, I0001 is a pointer to the F000x variable.
Initially I0001 is set equal to 2. When the subroutine call is executed, the indirect reference "I0001.F" is resolved to "F0002" (floating point variable with the index equal to the value of I0001). Later in the program, the main routine redefines I0001=3, so the next execution of the subroutine, the indirect reference "I0001.F" is resolved to "F0003".
Based on these principles, I rewrote the previous program into a subroutine based program:
Code:
PROGRAM 31
0010 S I0028=50 //Rapid Speed
0020 S I0029=20 //Reduced Speed
0030 TOOL 5 //Setup tool offset
0040 SUB 32
0050 ISP I0028 //Set speed
0060 MV E,J0100 //PTP move to safe location in the air
---------------------------------------------------First Place----------------
0070 S I0030=102
0080 S I0032=104
0090 SUB 30
---------------------------------------------------Second Place----------------
0100 S I0030=106
0110 S I0032=108
0120 SUB 30
---------------------------------------------------Third Place----------------
0130 S I0030=110
0140 S I0032=112
0150 SUB 30
---------------------------------------------------First Return----------------
0160 S I0030=104
0170 S I0032=102
0180 SUB 30
---------------------------------------------------Second Return----------------
0190 S I0030=108
0200 S I0032=106
0210 SUB 30
---------------------------------------------------Third Return----------------
0220 S I0030=112
0230 S I0032=110
0240 SUB 30
---------------------------------------------------End of Program----------------
0250 MV E,J0100 //PTP move to safe location in the air
0260 END //END of program
----------------------Pick & Place w/ Approach Points Subroutine--------------------------
//This subroutine completes a full pick and place action
//Approach positions are used for each pick and place location
//Robot moves to approach points at full speed defined by FLOAT 30
//Robot moves from approach points to pick/drop points at reduced speed defined by FLOAT 31
//Robot moves to pick point defined by INTEGER 30. Pick approach point must be stored in the position variable immediately preceding the pick point (e.g. P0101 = pick approach position, P0102 = pick position)
//INTEGER 31 is used for intermediate calculation of pick approach position
//Robot moves to drop point defined by INTEGER 32. Drop approach point must be stored in the position variable immediately preceding the drop point (e.g. P0103 = drop approach position, P0104 = drop position)
//INTEGER 33 is used for intermediate calculation of pick approach position
SUBROUTINE 30
0010 ISP I0028 //Set full speed from global rapid speed variable
0020 S P0100=I0030.P //Copy the pick point from the Position variable registers "P" at index defined by the value of I0030 to the working pick position P0100
0030 S I0031=I0030-1 //Subtract 1 from the pick position pointer
0040 S P0099=I0031.P //Copy the pick approach point from the Position variable registers "P" at index defined by the value of I0031 to the working pick approach position P0099
0050 MVS E,P0099 //Move linear to pick approach point
0060 ISP I0029 //Set full speed from global reduced speed variable
0070 MVS E,P0100 //Move linear to pick point
0080 SUB 31 //Call Close Gripper subroutine
0090 MVS E,P0099 //Move linear to pick approach point
0100 ISP I0028 //Set full speed from global rapid speed variable
0110 S P0100=I0032.P //Copy the pick point from the Position variable registers "P" at index defined by the value of I0030 to the working pick position P0100
0120 S I0033=I0032-1 //Subtract 1 from the pick position pointer
0130 S P0099=I0033.P //Copy the pick approach point from the Position variable registers "P" at index defined by the value of I0031 to the working pick approach position P0099
0140 MVS E,P0099 //Move linear to pick approach point
0150 ISP I0029 //Set full speed from global reduced speed variable
0160 MVS E,P0100 //Move linear to pick point
0170 SUB 32 //Call Open Gripper subroutine
0180 MVS E,P0099 //Move linear to pick approach point
0190 ISP I0028 //Set full speed from global rapid speed variable
0200 END
----------------------Close Gripper Subroutine--------------------------
//This subroutine completes a gripper close action
SUBROUTINE 31
0010 VON 5
0020 VOFF 6
0030 TIM 50
0040 END
----------------------Open Gripper Subroutine--------------------------
//This subroutine completes a gripper close action
SUBROUTINE 32
0010 VON 6
0020 VOFF 5
0030 TIM 50
0040 END
----------------------Variable definitions--------------------------
I0028 = Rapid Speed (default 50)
I0029 = Reduced Speed (default 20)
I0030 = Pick Point Pointer
I0031 = Internal Calculation (Pick Approach Pointer)
I0032 = Drop Point Pointer
I0033 = Internal Calculation (Drop Approach Pointer)
J0100 = Safe clearance position
P0099 = Internal Calculation (Pick/Drop Approach Position)
P0100 = Internal Calculation (Pick/Drop Position)
P0101 = Approach point to pick location 1
P0102 = Pick location 1
P0103 = Approach point to drop location 1
P0104 = Drop location 1
P0105 = Approach point to pick location 2
P0106 = Pick location 2
P0107 = Approach point to drop location 2
P0108 = Drop location 2
P0109 = Approach point to pick location 3
P0110 = Pick location 3
P0111 = Approach point to drop location 3
P0112 = Drop location 3
This reduced the total number of lines of code from 127 to 58 and each addition pick/place of a brick only adds 3 lines of code rather than 20.
A couple limitations of this is that you cannot complete indirect references or math outside of a "SETI" command line (lines starting with "S"). This means that the following line of code is invalid since you cannot resolve "I0030.P" to P.xxxx in the same line of code that you are trying to execute a move from.
You are also not allowed to complete more than one math operation per "SETI" command line, so the following is invalid since you are trying to add 3 values together:
Code:
0010 S I0001=I0002+I0003+2
This would be valid if written as:
Code:
0010 S I0001=I0002+I0003
0020 S I0001=I0001+2