Imaginations run wild with Java Lego robots

Learn to program the ultimate geek toy -- Lego Mindstorms -- in Java

The Lego Mindstorms Robotics Invention System (RIS) is a kit for building Lego robots. It includes two motors, two touch sensors, one light sensor, more than 700 Lego bricks, and a robot brain called the RCX. It's Lego's bid for the 11-and-up age group; the company hit this market better than it might have anticipated, seducing a lot of amateur roboticists in their 20s, 30s, and beyond. Although the 00 price tag sounds steep, it's an excellent value, considering what's contained in the set.

RIS also includes software for programming robots, a graphical environment called RCX Code. Using RCX Code, you can create robot programs by snapping together functional blocks, just like snapping together Lego bricks. You can download and store completed programs on the RCX via an infrared link (the same way your remote and your television set talk to each other). RCX Code is great for people who have never programmed, but it's limiting for experienced programmers.

RCX architecture

The RCX, the robotic brain, is a large brick that contains a microcontroller. You can attach three motors and three sensors simply by snapping special "wire bricks" on the RCX. An infrared port is used to communicate with your desktop computer.

Internally, the RCX contains 16KB of ROM and 32KB of RAM. The ROM contains low-level routines for the motors and sensors. You must load the RAM with firmware, which is also provided by Lego. This firmware (which I'll call the default firmware) contains a byte-code interpreter, which can run programs downloaded from RCX Code.

There are two categories of alternate programming environments for the RCX. The first uses the default firmware on the RCX and provides alternate programming environments on the desktop PC. A good example of this is NQC, a popular environment that lets you write robot programs using C-like source files. Those files are compiled and downloaded to the RCX, but it's still the default RCX firmware that runs the programs.

The second class of alternate programming environment uses replacement firmware and also provides a set of PC-side tools for programming. LeJOS falls into this category. LeJOS was created by Jose Solorzano, a developer and Lego robot enthusiast. LeJOS is the sophisticated cousin of TinyVM, Solorzano's first run at a Java environment for the RCX.

LeJOS provides replacement firmware that knows how to run leJOS programs. It also provides PC-side tools for compiling Java source code and downloading leJOS programs to the RCX.

LeJOS Java implementation

Only a small subset of the Java Virtual Machine and APIs can be implemented on a small device like the RCX. LeJOS includes just a few Java classes from java.lang, java.io, and java.util -- many of which will be familiar to Java programmers. That's one of the great things about leJOS; if you already know Java, you're a few steps up on the learning curve.

LeJOS installation

You can download the entire leJOS package from the leJOS homepage, http://lejos.sourceforge.net/. The page also contains links to installation instructions for both Linux and Windows. I'll be using the Windows version, but it will be much the same process for Linux users.

As of this writing, the current version is beta 3. It's distributed as a .tar.gz file for Linux and a .zip file for Windows. All you need to do is unpack the file, and then add the bin subdirectory to your PATH. (I assume you have already installed the Java 2 SDK. If not, go get it from http://java.sun.com/j2se/.)

Getting to know the tools

At this point, you'll probably want to build a robot that you can use for testing your leJOS programs. If you need some help, try following along with the building instructions found at http://www.oreilly.com/catalog/lmstorms/building/. I suggest building RoboTag, a basic tank-style robot with a bumper and a light sensor; it is an excellent test bed for programming.

RoboTag, one of the robots from The Unofficial Guide to Lego Mindstorms Robots , is a good platform for experimenting with code

LeJOS offers simple tools for compiling and downloading robot programs. If you've added leJOS's bin directory to your PATH, then you are ready to use the leJOS tools.

The first step is to download the leJOS firmware to the RCX. You only need to do this once. The RCX keeps the firmware in battery-backed RAM, so it is there even after you turn off the RCX. If you switch batteries, however, you will probably need to reinstall the firmware. Just use leJOS's lejosfirmdl command. The firmware download takes a few minutes; lejosfirmdl shows the percent complete as the download progresses.

C:\>lejosfirmdl
Use --help for options.
Transferring "/Apps/lejos/bin/../bin/lejos.srec" to RCX...
100%
C:\>

Now you're ready to start coding in Java. Type in the following simple program and save it in a file called HelloRCX.java:

import josx.platform.rcx.*;
public class HelloRCX {
  public static void main(String[] args) {
    Motor.A.forward();
    Motor.C.forward();
    try { Thread.sleep(2000); }
    catch (InterruptedException ie) {}
    Motor.A.stop();
    Motor.C.stop();
  }
}

Compiling this source code is a matter of running the regular javac and telling it to use the leJOS classes. Fortunately you don't have to think about it too much; just use the lejosc utility like this:

C:\>lejosc HelloRCX.java
C:\>

If there are any errors, lejosc will report them just like the regular javac compiler, providing both the error and the line number in the source code.

If lejosc is successful, it produces .class files from your .java source code. The next challenge is to get the class files down onto the RCX so you can run your program. LeJOS encapsulates this functionality in the lejos command-line tool. You do have to specify which port to use with an environment variable, like this:

C:\>set RCXTTY=COM2
C:\>lejos HelloRCX
C:\>

As the program is downloaded to the RCX, the RCX counts upward, starting from 1. How far it counts depends on how many classes are downloaded and the size of those classes.

This is a deceptively simple step. Behind the scenes, leJOS is compiling the class you specified into leJOS native code and downloading the native code to the leJOS firmware in the RCX. Further, it has to be smart enough to package and send any other classes that are referenced in your class. This is an important point. In this example, for instance, the Motor class will also be downloaded because you have used it in your code.

Once the program is downloaded, you can run it by pressing the Run button on the RCX. Go ahead and give it a try. Motors A and C will go on for two seconds, and then turn off.

API overview

Once you've mastered leJOS's tools, learning the APIs is straightforward. All the RCX-specific APIs are grouped together in the josx.platform.rcx package. Because the functionality of the leJOS APIs is very specific to the RCX, you'll see a lot of static methods and class constants. The Motor class, for example, has three static member variables representing the RCX's three motor outputs. Most of the remainder of this article is a tutorial on the leJOS APIs for controlling motors, configuring and reading sensors, using threads, controlling the display, and creating sound.

Controlling outputs

The RCX has three outputs that are represented by instances of josx.platform.rcx.Motor. Motor defines three static member variables, aptly named A, B, and C, one for each output. Using a motor is simply a matter of naming one of the Motor instances and calling one of its methods.

Outputs have a power and a mode that you can control. The mode is set by calling forward(), backward(), stop(), and flt(). Forward and backward modes set the motor running forward or backward, just as you'd expect. There are two ways to stop a motor, however. Calling stop() puts the output in stop or brake mode. A motor shaft attached to the output will not move; further, it resists movement, which is why it's called brake mode. The other mode is float; in this mode, the motor shaft doesn't move, but it doesn't resist movement either. If you drive a robot forward and then put the motors in float mode, the robot will coast to a stop rather than stop abruptly.

You can try this out in HelloRCX.java. Just call flt() instead of stop() to halt the motors; watch your robot glide gracefully to a stop.

An output's power can be set at a level of 1 to 7 using the setPower() method. Of course, the power of an output has meaning only if the mode is forward or backward.

Reading inputs

The RCX's versatile inputs can handle a wide variety of sensors, everything from simple passive touch sensors to powered rotation sensors. In leJOS, inputs are represented by instances of josx.platform.rcx.Sensor. Like the Motor class, Sensor provides three static member variables, S1, S2, and S3, that represent the three inputs.

To read a sensor properly, you must first configure the input. Each input has a type and a mode that can be set using the appropriately named setTypeAndMode() method. You can use constants defined in josx.platform.rcx.SensorConstants interface. For example, you can configure an input for a light sensor as follows:

Sensor.S2.setTypeAndMode(
    SensorConstants.SENSOR_TYPE_LIGHT,
    SensorConstants.SENSOR_MODE_PCT);

The type tells the RCX the electrical characteristics of the attached sensor, while the mode determines how the raw input signal is mathematically processed. In this case, I asked that the sensor values from the light sensor be returned as a percent.

You must explicitly configure an input if it is active (powered). Lego's light sensor is a good example of an active sensor; when it is configured properly, it emits a red light. You can turn on the power as follows:

Sensor.S2.activate();

Finally, to read the value from the input, call readValue().

Listening to sensors

LeJOS supports a JavaBeans-style event-listener mechanism, which lets you respond to changes in sensor values. Simply implement the SensorListener interface and register your listener with the sensor using addSensorListener(). Whenever the value of the input changes, your sensor listener's stateChanged() method will be invoked.

Here's a little program that beeps every time a touch sensor on input 1 changes state:

import josx.platform.rcx.*;
public class TouchBeeper {
  public static void main(String[] args) {
    Sensor.S1.setTypeAndMode(
        SensorConstants.SENSOR_TYPE_TOUCH,
        SensorConstants.SENSOR_MODE_BOOL);
    Sensor.S1.addSensorListener(new SensorListener() {
      public void stateChanged(Sensor source, int oldValue, int newValue) {
        Sound.beep();
      }
    });
  }
}

Threads and timing

Threads are handy in robot programming; you can create a new thread to listen for sensor events, or you can perform tricky calculations in a separate thread. Multithreading in leJOS is similar to multithreading in regular Java. It's based on java.lang.Thread, which has a run() method containing the code that will be executed in a new thread. It also has a start() method for kicking off the new thread.

LeJOS lacks the java.lang.Runnable interface, so the only way you can create new threads is by subclassing Thread and defining the run() method.

LeJOS also features a timer class and a timer listener interface in the josx.util package. The basic idea is to set up a timer and kick it off. When the timer fires, all registered listeners are notified. For more details, check the API documentation in Resources.

Using the display

The RCX includes a small display. LeJOS has several classes that you can use for showing things on the display. The capabilities are pretty impressive; basically, you can control every segment of the display. I'll cover only a couple of the simpler methods here.

First, the josc.platform.rcx.LCD class has a static setNumber() method that accepts an integer and shows it on the screen. You can also use clear() to turn all segments of the display off, although you'll need to call refresh() to see the effects. The documentation states that you need to call refresh() after "certain operations," but it's not specific about which ones. If you are trying to change items on the display and don't see results, try calling refresh(); it may help.

Finally, you can display text on the display, although it's not particularly legible and there's only space for five characters. The following example shows how to display a text string:

    TextLCD.print("Hello");

Try it out! See how many five-letter words you can think of.

Making music

The RCX is also capable of playing sounds. You can play arbitrary tones or some prepackaged sequences. Static methods in the josx.platform.rcx.Sound class expose this functionality.

The simplest methods are the static beep(), twoBeeps(), buzz(), and beepSequence() methods, none of which accepts a parameter. If you want to play a song, you can pass the frequencies and durations of the notes to playTone().

1 2 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more