Table of contents:
This is an extension to the Tcl interpreter to let you issue commands to the RCX interactively or compile bytecode programs, download and run them. It was originally based on Tcl RCX, by Laurent Demailly. The bytecode compilation functions were made possible mainly by the excellent reverse engineering and RCX bytecode documentation provided by Kekoa Proudfoot on his RCX Internals web page. If you are interested in using the RCX to its greatest potential, Russell Nelson's Lego Mindstorms Internals web page is the place to go.
Programming for the RCX with these Tcl commands lets you go well beyond the capabilities of the Mindstorms programming environment. Since this program outputs RCX bytecode as implemented by the Mindstorms firmware, you will need to download the firmware to your RCX before downloading and running any of your bytecode programs. To accomplish a firmware download on platforms other than Windows you will need another tool - again, I suggest the Lego Mindstorms Internals web page as a reference. I will be adding the firmware download capability to the compiler soon.
To get started, fire up a Tcl shell and try this:
% source rcx.tcl
% connect
% ping
OK
% motor a forward
OK
% motor a power 7
OK
% motor a on
OK
% motor a off
OK
%
This is an example of a simple interactive session to turn an RCX motor on and off. You may need to specify the name of the serial port for your infrared tower to the connect
command by using connect com2
or connect /dev/ttyd
, for example.
The compiler can operate in three modes:
immediate | Sends commands to the RCX for immediate execution and usually reads and interprets the response. | |
deferred | Compiles commands as an RCX program that can be downloaded and run. | |
inspect | Compiles commands and prints the resulting bytecode. I use this for testing and debugging purposes. |
immediate
mode. You can explicitly set the mode of operation with a command such as: set rcx::mode immediate
begin
commands put it into deferred
mode and the end
command goes back to immediate
mode.
Many of the commands require you to specify a data source to operate with. Here is a summary of these specifiers:
Source Type | Examples | Meaning | Legal Values | |||
Register | r15 | The value stored in a named register | r0 r1 .. r31 | |||
Timer | timer 0 | The value of a timer | timer 0, timer 1, timer 2 | |||
Immediate | 5 | A numeric value | any 16-bit number | |||
Motor | motor a | The state of a motor | motor a, motor b, motor c | |||
Random | random 10 | A random value from 0 to n | 0 < n < 65536? | |||
Program | program | The current program number | program | |||
Sensor | sensor 2 | The value of a sensor input | sensor 1, sensor 2, sensor 3 | |||
Sensor Type | sensorType 1 | The type of sensor on a given input | sensorType 1, sensorType 2, sensorType 3 | |||
Sensor Raw | sensorRaw 3 | The raw value of a sensor input | sensorRaw 1, sensorRaw 2, sensorRaw 3 | |||
Watch Time | watch | The number of minutes on the RCX watch | watch | |||
Message | message | The current RCX message | message |
Compilation commands: | ||
label: |
Define a program label | V |
begin task task |
Begin defining RCX task number task | V |
begin subroutine sub |
Begin defining RCX subroutine number sub | V |
loop for count |
Start a loop for count iterations | V |
loop end |
End a loop | V |
end |
End compilation | V |
beam prog |
Beam compiled program to RCX as program prog | V |
I/O functions: | ||
ping |
See if RCX responds | V |
transmitter short|long |
Set transmitter range | V |
rget source |
Get value of source | V |
getVersion |
Get ROM and firmware versions | V |
getBattery |
Get battery voltage | V |
watch hours minutes |
Set time on watch | V |
display source |
Set display to show device source | V |
tone freq duration |
Play tone freq for duration | V |
beep sound |
Play sound number sound (0..5) | V |
datalog size size |
Set datalog size to size | V |
datalog add source |
Next Datalog entry = source | V |
message set n | Set message buffer to n | V |
message clear |
Clear Message buffer | V |
message send source |
Send message source | V |
Utility functions: | ||
wait source |
Wait for source 100ths of a second | V |
clear timer timer |
Clear timer number timer | V |
power off |
Power off the RCX | V |
power delay minutes |
Set power-down delay to minutes | V |
Motor and Sensor functions: | ||
motor motors forward|reverse|flip |
Set motor direction | V |
motor motors power source |
Set power of motors to value from source | V |
motor motors on|off|float |
Set motors to on, off or float | V |
sensor 1|2|3 reads type |
Set sensor type | V |
sensor 1|2|3 uses mode [slope] |
Set sensor mode | V |
sensor 1|2|3 clear orclear sensor 1|2|3 |
Clear Sensor value | V |
Math functions: | ||
rset register source |
register = source | V |
calc register op source |
register = register op source [op is: = + - / * sgn abs and or ] | V |
Flow of control: | ||
jmpnear offset|label |
Branch Always Near | V |
jmp offset|label |
Branch Always Far | V |
tbr { source1 op source2 } offset|label |
Test and branch if <= >= == != | V |
call sub |
Call subroutine sub (0..7) | V |
ret |
Return from subroutine | V |
start task |
Start task task | V |
stop task |
Stop task task | V |
stop |
Stop all tasks | V |
program prog |
Set program number to prog | V |
label:
A word ending with a colon is interpreted as a program label, which can be used as a destination for jmp, jmpnear or tbr instructions.
beam prog
The latest compiled program, including all its tasks and subroutines, will be beamed to the RCX and stored in the program slot (1-5) specified by prog.
beep sound
Causes the RCX to emit one of six built-in beep sounds:
sound My creative sound name 0 pip 1 mee-meep 2 arpeggio down 3 arpeggio up 4 buzz 5 fast arpeggio up
begin task task
begin subroutine sub
Begin compilation of RCX bytecode.
begin task
is used to define RCX tasks andbegin subroutine
defines subroutine blocks.
calc register op source
Perform register arithmetic. The result of the calculation goes back into the register.
Here are some examples:
- register specifies a register (r0-r31) to use.
- op can be one of:
=
Set register equal to source +
Add source to register -
Subtract source from register /
Divide register by source *
Multiply register by source sgn
Set register to -1 if source < 0, 0 if source = 0, 1 if source > 0 abs
Set register to absolute value of source and
Bitwise and or
Bitwise or - source specifies a data source. For all operations except
=
, only immediate and register sources are allowed.
calc r0 = 5
Set r0 equal to 5 calc r0 * r10
r0 = r0 * r10 calc r0 = timer 0
Set r0 equal to the value of timer 0 calc r30 = sensor 2
Set r30 equal to the reading from sensor 2
call sub
Call subroutine number sub (0-7) in the current program. The subroutine can return with the ret command.
datalog size size
datalog add source
datalog upload first count
I have not tested the
datalog
functions yet.
display source
Set the RCX display to show the device specified by the value of source. The mapping from values to devices is:
0 Time on the Watch 1 Value of Sensor 1 2 Value of Sensor 2 3 Value of Sensor 3 4 Power of Motor A 5 Power of Motor B 6 Power of Motor C
end
End bytecode compilation. This command will perform some checks on your compiled program and switch to "immediate" mode.
getBattery
Read the battery voltage from the RCX and print the result.
getVersion
Read the ROM and firmware version numbers from the RCX, then print the result.
jmp offset|label
jmpnear offset|label
Go to the program offset or label specified and continue execution. You can either specify an offset in bytes (relative to the jmp instruction) or a program label as the destination.
jmpnear
generates smaller bytecode but is limited to offsets between -127 and 128.
loop for count
loop end
Using
loop
lets you repeat a section of code a certain number of times. The repeat count count can be specified as Timer, Immediate or Random.For example:
will beep 5 times.loop for 5
beep 1
loop end
message send source
message set n
message clear
message send source
Broadcast a message via the infrared port. The message consists of a byte of data specified by source.
motor motors forward|reverse|flip
motor motors power source
motor motors on|off|float
These are motor control functions. The motors argument specifies which motors you wish to control. This should be a string of letters containing
A
,B
and/orC
. Either upper or lower case letters work.
motor motors forward|reverse|flip
Control the direction of one or more motors. The motor directions are:
forward
Have motor(s) turn in the 'Forward' direction reverse
Have motor(s) turn in the 'Reverse' direction flip
Flip the direction of motor(s) from its previous value
motor motors power source
Set the power for the specified motor(s) to the value of source. Valid source types are Timer, Immediate and Random. Valid power levels are from 0 to 7.
motor motors on|off|float
Turn a motor on, turn it off or "float" it, which lets the shaft spin freely.If you just say
motor
, without any arguments, the default ismotor ABC float
as a kind of "emergency stop" for when your robot gets into trouble.
ping
Send a test signal to the RCX. This is useful to be sure that IR communication between the PC and RCX is working.
power off
power delay minutes
power off
Turn off the RCX.
power delay minutes
Set the RCX power-down delay to the specified number of minutes, which should be from 0 to 59.
program prog
Set the current program number to prog. Valid program numbers are 1 through 5.
ret
Return from the current subroutine.
rget source
Get the value of source from the RCX and print the result. Immediate and Random sources are not allowed.
For example:
% rget r0
value is 1
% rget timer 1
value is 12287
rset register source
Set the specified register equal to the value of source. This is another way of saying
calc register = source
.
sensor 1|2|3 reads type
sensor 1|2|3 uses mode [slope]
sensor 1|2|3 clear
clear sensor 1|2|3
These commands are used to set the methods for reading sensors.
sensor 1|2|3 reads type
Set the type of sensor attached to the given port:
type Meaning raw
raw sensor value touch
touch sensor temp
temperature sensor light
light sensor rotation
rotation sensor
sensor 1|2|3 uses mode [slope]
Set the mode for reading sensor data.
I am still experimenting with the slope. Apparently it is a value that determines where the threshold between 0 and 1 is for the boolean modes.
mode Meaning raw
Raw sensor value, 0 to 1023 bool
0 or 1 edge
Like bool
, but reads number of trasitions between 0 and 1pulse
Like bool
, but reads number of transitions to 0percent
Reading scaled from 0 to 100 deg_c
Degrees C deg_f
Degrees F angle
Angle reading, in 1/16ths of a turn
sensor 1|2|3 clear
clear sensor 1|2|3
Use either of these forms to clear the transition count for a sensor usingedge
orpulse
modes.Some common usages would be:
sensor 1 reads touch
sensor 1 uses bool
sensor 2 reads light
sensor 2 uses percent
start task
Start running task number task. In an RCX program, use this to start other defined tasks in your program.
You can also usestart 0
interactively to have the RCX run the current program.
stop task
stop
stop task
will stop running the specified task.
stop
will stop running all tasks in the current program.
tbr { source1 op source2 } offset|label
Test and branch.
source1 is compared to source2 with one of these operators:
If the result is true, the program continues execution at the location specified by the label or offset (in bytes relative to the
<=
>=
==
!=
tbr
instruction). If no offset is specified, the default is 0, which means to go back to thetbr
test. This is useful for waiting for a certain condition, such as a sensor having the given value.
clear timer timer
Clear the value of the specified timer. Valid timer numbers are 0, 1 and 2.
tone freq duration
Play a tone. The frequency is in Hz and the duration in 1/100ths of a second.
transmitter short|long
Set the RCX infrared transmitter to short or long range.
wait source
Wait for the amount of time given by the value of source, in 1/100ths of a second.
Note that the wait block in Mindstorms RCX Code uses units of 1/10th of a second instead.
watch hours minutes
Set the time on the RCX watch to hours and minutes.
Here are some tricks I've found that make writing RCX programs easier:
Create on-the-fly Tcl procedures that issue RCX commands. For instance, with a dual motor differential steering robot I recently built, I can define these commands right in the Tcl shell:
proc f { motor AC forward ; motor AC on }
proc b { motor AC reverse ; motor AC on }
proc l { motor A reverse ; motor C forward ; motor AC on }
proc r { motor A forward ; motor C reverse ; motor AC on }
proc s { motor AC off }
Then, in immediate mode, I can give f
, b
, l
, r
and s
commands to drive around the room!
tbr
can be used to wait until a sensor value meets a certain condition:
tbr { sensor 1 == 0 } ;# Wait until switch is pressed
tbr { sensor 2 >= 45 } ;# Wait until the light goes off
Use Tcl variables to name sources, tasks and subroutines:
Then use the defined values:
set speed r0 ;# Driving speed set bumper 1 ;# Bumper watch task set turn 0 ;# Avoidance subroutine
begin task 0 rset $speed 7 motor ABC power $speed start $bumper ... begin task $bumper tbr { sensor 1 == 0 } call $turn ... begin subroutine $turn ...