Tcl RCX Bytecode Compiler

Table of contents:

Description

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.

Using the Compiler

Quick Start

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.

Operating Modes

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.
When you first start up the compiler and connect to the serial port it defaults to immediate mode. You can explicitly set the mode of operation with a command such as:
    set rcx::mode immediate
although, in practice, the operating mode is set automatically by the commands you use. For instance, the begin commands put it into deferred mode and the end command goes back to immediate mode.

Source Specifiers

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

Commands by Function:

The V links point to the command description in Command Reference.
Compilation commands:
label: Define a program labelV
begin task task Begin defining RCX task number taskV
begin subroutine sub Begin defining RCX subroutine number subV
loop for count Start a loop for count iterationsV
loop end End a loopV
end End compilationV
beam prog Beam compiled program to RCX as program progV
  
I/O functions:
ping See if RCX respondsV
transmitter short|long Set transmitter rangeV
rget source Get value of sourceV
getVersion Get ROM and firmware versionsV
getBattery Get battery voltageV
watch hours minutes Set time on watchV
display source Set display to show device sourceV
tone freq duration Play tone freq for durationV
beep sound Play sound number sound (0..5)V
  
datalog size size Set datalog size to sizeV
datalog add source Next Datalog entry = sourceV
  
message set n Set message buffer to nV
message clear Clear Message bufferV
message send source Send message sourceV
  
Utility functions:
wait source Wait for source 100ths of a secondV
clear timer timer Clear timer number timerV
power off Power off the RCXV
power delay minutes Set power-down delay to minutesV
  
Motor and Sensor functions:
motor motors forward|reverse|flip Set motor directionV
motor motors power source Set power of motors to value from sourceV
motor motors on|off|float Set motors to on, off or floatV
  
sensor 1|2|3 reads type Set sensor typeV
sensor 1|2|3 uses mode [slope] Set sensor modeV
sensor 1|2|3 clear   or
clear sensor 1|2|3
Clear Sensor valueV
  
Math functions:
rset register source register = sourceV
calc register op source register = register op source
[op is: = + - / * sgn abs and or]
V
  
Flow of control:
jmpnear offset|label Branch Always NearV
jmp offset|label Branch Always FarV
tbr { source1 op source2 } offset|label Test and branch if <= >= == !=V
  
call sub Call subroutine sub (0..7)V
ret Return from subroutineV
  
start task Start task taskV
stop task Stop task taskV
stop Stop all tasksV
  
program prog Set program number to progV

Command Reference:

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 and begin 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:
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:

loop for 5
beep 1
loop end
will beep 5 times.


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/or C. 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 is motor 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.
mode Meaning
raw Raw sensor value, 0 to 1023
bool 0 or 1
edge Like bool, but reads number of trasitions between 0 and 1
pulse Like bool, but reads number of transitions to 0
percent Reading scaled from 0 to 100
deg_c Degrees C
deg_f Degrees F
angle Angle reading, in 1/16ths of a turn
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.

sensor 1|2|3 clear
clear sensor 1|2|3

Use either of these forms to clear the transition count for a sensor using edge or pulse 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 use start 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 the tbr 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.


Tips and Tricks

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:

set speed r0              ;# Driving speed
set bumper 1              ;# Bumper watch task
set turn 0                ;# Avoidance subroutine
Then use the defined values:
begin task 0
rset $speed 7
motor ABC power $speed
start $bumper
...
begin task $bumper
tbr { sensor 1 == 0 }
call $turn
...
begin subroutine $turn
...

Future Development



©1998 Peter Pletcher