Program
commands are like chores, whether it is to turn on an output,
set a velocity, start a move or whatever. A program is a list
of these chores. When a programmed SmartMotor is powered-up or
its program is reset with the Z command, it will execute its program
in order from the beginning to the end.
RUN
Execute stored user program
If
you reset your program with a Z command you will erase all previous
variables and mode changes for a fresh start. Alternatively you
can use the RUN command to start the program in which case the
state of the motor is unchanged and your program will be invoked.
RUN?
Halt program if no RUN issued
To
keep your downloaded program from executing at power-up start
your program with the RUN? command. It will prevent the program
from starting when power is applied, but it will not prevent the
program from running when the SmartMotor sees a RUN command from
a host over the RS-232 input.
Once
your program is running, there are a variety of commands that
can redirect program flow and most of those can do so based on
certain conditions. How you set up these conditional decisions
determines what your programmed SmartMotor will do, and exactly
how smart" it will actually be.
GOTO#
Redirect program flow
C# Subroutine
label, C0-C999
The
most basic commands for redirecting program flow, without inherent
conditions, are GOTO# in conjunction with C#. Labels are the letter C followed by a number (#) between
0 and 999 and are inserted in the program almost as place markers.
If a label, C1 for this example, is placed in your program and
you put that same number at the end of a GOTO command, GOTO1,
the program flow will be redirected to label C1 and the program
will proceed from there.
You
can use as many as a thousand labels in your program (0 - 999),
but, the more GOTO commands you use, the harder your code will
be to debug or read. Try using only one and use it to create the
infinite loop necessary to keep your program running indefinitely,
as some embedded programs do. Put a C1 label at the beginning
of your program and a GOTO1 at the end and every time the GOTO1
is reached the program will loop back to label C1 and start over
from that point until the GOTO1 is reached again which will start
the process all over at C1 and so on. You can write any program
with only one GOTO. It might be a little harder, but it will tend
to force you to better organize your program, which in turn will
make it easier for others to read and for anyone to change.
END
End program execution
If
you want your program to stop, simply send an END command and
execution will stop at that point. An END command can also be
sent by the host to intervene and stop a program running within
the motor. The program in your SmartMotor is never erased until
you download a new one. If you want to erase the program on your
motor download only the END command as if it were a new program
and that's the only command that will be left on your SmartMotor until you download a new program.
GOSUB#
Execute a subroutine
RETURN
Return from subroutine
Just
like the GOTO# command, the GOSUB# command, in conjunction with
a C# label, will also redirect program execution in the same way.
But, unlike the GOTO# command, the C# label needs a RETURN command
at the end of the subroutine which will return the program to
the location of the GOSUB# command that initiated the command.
As an example; you want your SmartMotor to perform the same routine
periodically throughout your program. For this we'll use GOSUB5
as an example which will send your program to the C5 label's subroutine.
The subroutine will execute until the RETURN is reached which
will send your program back to the GOSUB5 point where the diversion
occurred and your program will continue on from there running
the commands after the GOSUB5. If another GOSUB5 command is reached
your program will return to the same subroutine at the C5 label
and run the subroutine. But, now when it reaches the RETURN command
it will return to the latest GOSUB5 command that sent it to the
C5 label and forge on from there. The GOSUB5 command can be invoked
as many times as you need throughout your program and will always
return to the GOSUB5 point where the command was issued last when
it reaches the RETURN command. You can have as many as one thousand
different subroutines (0 - 999) and access each one as many times
as you want throughout your program.
By
encapsulating a piece of code into a subroutine, the code can
be called upon repeatedly and from all different points throughout
the rest of the program. Organizing your code into multiple subroutines
is a good practice.
The
commands that can conditionally direct program flow to different
areas use a constant [#] like 1 or 25, a variable like a or al[#]
or a function involving constants and/or variables a+b or a/[#].
Only one operator can be used in a function. A list of those operators
is as follows:
+ Addition
- Subtraction
* Multiplication
/ Division
== Equals (use two =)
!= Not equal
< Less than
> Greater than
<= Less than or equal
>= Greater than or equal
& Bitwise AND (see appendix A)
| Bitwise OR (see appendix A)
WHILE,
LOOP
The
most basic looping function is a WHILE command. The WHILE is followed
by an expression that determines whether the code between the
WHILE and the following LOOP command will execute or be passed
over. While the expression is true, the code will execute. An
expression is true when it is non-zero. If the expression results
in a zero" then it is false. The following are valid WHILE structures:
WHILE 1 ‘1
is always true
UA=1 ‘Set output to 1
UA=0 ‘Set output to 0
LOOP ‘Will loop forever
a=1 ‘Initialize variable
‘a'
WHILE a
‘Starts out true
a=0
‘Set ‘a' to 0
LOOP ‘This never loops back
a=0 ‘Initialize variable
‘a'
WHILE a<10 ‘a
starts less
a=a+1 ‘a grows by 1
LOOP ‘Will loop back 10x
The
task or tasks within the WHILE loop will execute as long as the
function remains true.
The
BREAK command can be used to break out of a WHILE loop, although
that somewhat compromises the elegance of a WHILE statement's
single test point, making the code a little harder to follow.
The BREAK command should be used sparingly or preferably not at
all in the context of a WHILE.
If
you want a portion of code to execute only once based on a certain
condition then use the IF command.
IF,
ENDIF
Once
the execution of the code reaches the IF command, the code between
that IF and the following ENDIF will execute only when the condition
directly following the IF command is true. For example:
a=UAI ‘Variable
‘a' set 0,1
a=a+UBI ‘Variable ‘a'
0,1,2
IF a==1 ‘Use double = test
b=1 ‘Set ‘b' to one
ENDIF ‘End IF
Variable
b will only get set to one if variable a is equal to one. If a
is not equal to one, then the program will continue to execute
using the command following the ENDIF command.
Notice
also that the SmartMotor language uses a single equal sign (=)
to make an assignment, such as where variable a is set to equal
the logical state of input A. Alternatively, a double equal (==)
is used as a test, to query whether a is equal to 1 without making
any change to a. These are two different functions. Having two
different syntaxes has farther reaching benefits.
ELSE,
ELSEIF
The
ELSE and ELSEIF commands can be used to add flexibility to the
IF statement. What if you wanted to execute different code for
each possible state of variable a. You could write the program
as follows:
a=UAI ‘Variable
‘a' set 0,1
a=a+UBI ‘Variable ‘a'
0,1,2
IF a==0
‘Use double ‘=' test
b=1 ‘Set ‘b' to one
ELSEIF a==1
c=1 ‘Set ‘c' to one
ELSEIF a==2
c=2 ‘Set ‘c' to two
ELSE ‘If not
0, 1, or 2
d=1 ‘Set ‘d' to one
ENDIF ‘End IF
There
can be many ELSEIF statements, but at most one ELSE. If the ELSE
is used, it needs to be the last statement in the structure before
the ELSEIF. You can also have IF structures inside IF structures.
That is called nesting" and there is no practical limit to the
number of structures you can nest within one another.
SWITCH,
CASE, DEFAULT, BREAK, ENDS
Long,
drawn out IF structures can be cumbersome, however, and burden
the program, visually. In these instances it can be better to
use the SWITCH structure. The following code would accomplish
the same thing as the previous program:
a=UAI ‘Variable
‘a' set 0,1
a=a+UBI ‘Variable ‘a'
0,1,2
SWITCH a
‘Begin SWITCH
CASE 0
b=1 ‘Set ‘b' to one
BREAK
CASE 1
c=1 ‘Set ‘c' to one
BREAK
CASE 2
c=2 ‘Set ‘c' to two
BREAK
DEFAULT ‘If not 0 or 1
d=1 ‘Set ‘d' to one
BREAK
ENDS ‘End SWITCH
Just
as a rotary switch directs electricity, the SWITCH structure directs
the flow of the program. The BREAK statement then jumps the code
execution to the code following the associated ENDS command. The
DEFAULT command covers every condition other than those listed.
It is optional.
TWAIT
Wait during trajectory
The
TWAIT command pauses program execution while the motor is moving.
Either the controlled end of a trajectory, or the abrupt end of
a trajectory due to an error, will terminate the TWAIT waiting
period. If you had a succession of move commands without this
command, or similar waiting code between them, the commands would
overtake each other because the program advances, even while moves
are taking place. The following program has the same effect of
the TWAIT command, but has the added virtue of allowing you to
program other things during the wait, instead of just waiting.
WHILE Bt
‘While trajectory
LOOP ‘Loop
back
WAIT=exp
Wait (exp) sample periods
There
will probably be circumstances where you will want to pause program
execution for a specific period of time. Time, within the SmartMotor,
is tracked in terms of servo sample periods. Unless otherwise
programmed with the PID# command, the sample rate is about 4KHz.
WAIT=4000 would wait about one second. WAIT=1000 would wait for
about one quarter of a second. The following code would be the
same as WAIT=1000, only it will allow you to execute code during
the wait if you place it between the WHILE and the LOOP.
CLK=0
‘Reset CLK to 0
WHILE CLK<1000 ‘CLK
will grow
IF UAI==0
‘Monitor input A
GOSUB911 ‘If input low
ENDIF ‘End the IF
LOOP ‘Loop
back
The
above code example will check if input A ever goes low, while
it is waiting for the the CLK variable to count up to 1000.
STACK
Reset the GOSUB return stack
The
STACK is where information is held with regard to nesting of subroutines
(nesting is when one or more subroutines exist within others).
In the event you direct program flow out of one or more nested
subroutines, without executing the included RETURN commands, you
will corrupt the stack. The STACK command resets the stack with
zero recorded nesting. Use it with care and try to build your
program without using the STACK command.
One
possible use of the STACK command might be if your program used
one or more nested subroutines and an emergency occurred, the
program or operator could issue the STACK command and then a GOTO
command which would send the program back to a label at the beginning.
Using this method instead of a RESET command would retain the
states of the variables and allow further specific action to resolve
the emergency.