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 immediatebegin 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 progThe 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 soundCauses 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 subBegin compilation of RCX bytecode.
begin taskis used to define RCX tasks andbegin subroutinedefines subroutine blocks.
calc register op sourcePerform 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 sgnSet register to -1 if source < 0, 0 if source = 0, 1 if source > 0 absSet register to absolute value of source andBitwise and orBitwise or - source specifies a data source. For all operations except
=, only immediate and register sources are allowed.
calc r0 = 5Set r0 equal to 5 calc r0 * r10r0 = r0 * r10 calc r0 = timer 0Set r0 equal to the value of timer 0 calc r30 = sensor 2Set r30 equal to the reading from sensor 2
call subCall 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 countI have not tested the
datalogfunctions yet.
display sourceSet 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
endEnd bytecode compilation. This command will perform some checks on your compiled program and switch to "immediate" mode.
getBatteryRead the battery voltage from the RCX and print the result.
getVersionRead the ROM and firmware version numbers from the RCX, then print the result.
jmp offset|label
jmpnear offset|labelGo 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.
jmpneargenerates smaller bytecode but is limited to offsets between -127 and 128.
loop for count
loop endUsing
looplets 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|floatThese are motor control functions. The motors argument specifies which motors you wish to control. This should be a string of letters containing
A,Band/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:
forwardHave motor(s) turn in the 'Forward' direction reverseHave motor(s) turn in the 'Reverse' direction flipFlip 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 floatas a kind of "emergency stop" for when your robot gets into trouble.
pingSend 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 progSet the current program number to prog. Valid program numbers are 1 through 5.
retReturn from the current subroutine.
rget sourceGet 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 sourceSet 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|3These 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 rawraw sensor value touchtouch sensor temptemperature sensor lightlight sensor rotationrotation 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 rawRaw sensor value, 0 to 1023 bool0 or 1 edgeLike bool, but reads number of trasitions between 0 and 1pulseLike bool, but reads number of transitions to 0percentReading scaled from 0 to 100 deg_cDegrees C deg_fDegrees F angleAngle 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 usingedgeorpulsemodes.Some common usages would be:
sensor 1 reads touch
sensor 1 uses bool
sensor 2 reads light
sensor 2 uses percent
start taskStart running task number task. In an RCX program, use this to start other defined tasks in your program.
You can also usestart 0interactively to have the RCX run the current program.
stop task
stop
stop taskwill stop running the specified task.
stopwill stop running all tasks in the current program.
tbr { source1 op source2 } offset|labelTest 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
<=>===!=tbrinstruction). If no offset is specified, the default is 0, which means to go back to thetbrtest. This is useful for waiting for a certain condition, such as a sensor having the given value.
clear timer timerClear the value of the specified timer. Valid timer numbers are 0, 1 and 2.
tone freq durationPlay a tone. The frequency is in Hz and the duration in 1/100ths of a second.
transmitter short|longSet the RCX infrared transmitter to short or long range.
wait sourceWait 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 minutesSet 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 subroutinebegin task 0 rset $speed 7 motor ABC power $speed start $bumper ... begin task $bumper tbr { sensor 1 == 0 } call $turn ... begin subroutine $turn ...