Robotics Lab #1

Installing and programming in leJOS


810:161:02, Artificial Intelligence Robotics Lab

Fall Semester 2006


Due: Monday, September 11th, 2:00 PM


Power point slides of this material. 


Goals

This week's goals are to teach you some of the odds and ends that you will need to know in order to use leJOS to program your robots.  It will include a brief introduction to command line work in DOS, information on how to set up the RCX brick to accept leJOS code, and how to actually program and run leJOS based code. 


Before I get started too much - A little bit about using the command line in DOS

During the "lecture" component for this lab I will demo the following at the appropriate time.  They are given here just as a quick reference.

The best way to get a command prompt is by selecting "Start->Run" and typing "cmd"

Once you get a prompt, there are only a handful of commands you should need

 

 

 

 

 


What is leJOS and why use it?

leJOS (pronounced like you might say lay-host if you didn't pronounce the 't') is a Java based "firmware" for the LEGO Mindstorms.  In fact, leJOS stands for LEGO Java Operating System.  You write code in a language that is almost Java, compile this to leJOS byte code, install the byte code on your RCX brick, and let a leJOS interpreter on the brick (stored in RAM) interpret this code down to the standard RCX machine language (stored in ROM).  This interpreter is relatively small (~17 KB) yet allows you to write some fairly powerful code.

leJOS is not without its problems.  Some of these are trivial, and some are serious.  Of minor impact is the fact that leJOS is NOT Java.  That is, it does not support all of the Java APIs.  For example, switch statements, Long Arithmetic, and Java.lang.class are not supported in any capacity.  Having a larger impact is the fact there is no garbage collection.  While this may not SEEM like a big deal, it will become one.  That is tied into the largest problem - RAM limits on the RCX

Recall that last week I mentioned that the RCX brick has 32 KB of RAM.  While this is accurate, it is misleading.  First of all, even if you were running the basic LEGO RCX Firmware, you would not have access to all 32 KB.  The routines stored in ROM require 4 KB of RAM to perform their operations.  Thus, at best, you would have access to 28 KB.  The current implementation of the leJOS interpreter has a 17 KB footprint.  This means that you have, at best, 11 KB of memory to work with once you have installed leJOS.  Most of the sources I read state that this is a lot closer to 9 KB.  This is 9 KB to not only load and store your byte code, but also store all of your data used by the code.  This is where garbage collection becomes a problem.  Create an array of Doubles, and memory may disappear fast.


leJOS-enable your RCX

To enable your RCX for the execution of leJOS programs, you will have to install the leJOS operating system. leJOS will be loaded into volatile RAM.  That means that it will stay there as long as there are charged batteries in the RCX.  Anytime the RCX loses power, you will need to re-enable leJOS.  Fortunately, this is easily done:

  1. Place the IR sensor of the RCX in front of the IR Tower
  2. Cover them both with the green bin (this is only necessary when there are several people in the lab).
  3. Turn on the RCX
  4. Open a command shell and change to the bin directory of your leJOS installation
  5. call firmdl.bat
  6. Notice that the screen of both the computer and the RCX should indicate progress. The counter on your RCX brick will continue until approximately 1662.
  7. You will know the download of leJOS was successful if you see “firmware unlocked”  Conversely, response=-X (often 5) means it failed.  If this happens, don't panic.  Simply try step 5 again.
  8. One last way to know that the transfer was successful is that the  “prompt” on the RCX is a number in the format X.Y .  This is the voltage on your batteries (6x1.5 means ideal voltage is 9.0).  You will probably be fine as long as this voltage stays relatively high.  However, somewhere around 5.5 volts we start to see undependable behavior.  It is time to recharge the batteries (and of course, repeat this whole section when you reinstall the batteries).

If the download doesn't work, make sure that

The tower should blink green, when you start firmdl.

The original LEGO® firmware isn't deleted from the RCX. Hence you may re-activate it by just removing the batteries for a few minutes and replacing it.


Create and Run your first leJOS program

There's a simple "Hello World" style example program available in the examples\hworld section of the leJOS tree:


            import josx.platform.rcx.*;

            /**
             * @author Ryan VanderBijl
             */

            /* This class uses char[] to display text on the LCD.
             * Strings aren't really supported by TinyVM. :-(
             * 
             * This program, after d/ling, waits for you to press the RUN
             * button, and then displays "hello", for a small delay, and then
             * displays "world". (Then a small delay, and then it returns to
             * the TinyVM OS).
             */

            public class HelloWorld
            {
              public static void main (String[] aArg)
              throws Exception
              {
                 LCD.clear();
                 TextLCD.print ("hello");
                 Thread.sleep(2000);
                 TextLCD.print ("world");
                 Thread.sleep(2000);
              }
            }
        

To run this program, you will:

  1. Open a command shell and change to the examples\hworld directory of your leJOS installation
  2.  

  3. Compile it using lejosc instead of javac:
    lejosc HelloWorld.java

    NOTE: When you write your own Java code, you will probably be using jGrasp.  That being the case, as you write and "test compile" your code you may absolutely use the javac command by using the compile button/comand within jGrasp.  However, the .class files created from here will not be recognized by later steps in this process.  Therefore, you must always recompile using lejosc.

     

  4. Create a binary file containing the linked program with lejos

    lejos -o HelloWorld.bin HelloWorld

     

  5. Download it to the RCX using leJOSrun:
    lejosrun HelloWorld.bin
  6.  

  7. Just like when you downloaded leJOS itself, the progress of the download is displayed in the command shell and on the display of the RCX; the RCX will double beep when the download is complete and displays a standing man
  8.  

  9. Press Run to start the program; The words "hello" and afterwards "world" will be displayed on the RCX

 

If lejosc or lejos isn't found, make sure your PATH variable is set accordingly.

If the leJOS classes aren't found, check your CLASSPATH variable.

The two steps of linking and downloading (steps 3 and 4) may be done in one with
lejos HelloWorld

However, I suggest doing it in two steps.  I have simply discovered that there are less errors, and if they do occur it is easier to tell where they are (not to mention it is faster to reload a working program if it is already saved as a binary file).


More helpful info about leJOS code

Remember when you first started learning Java?  For many of you the first program you saw was some variant of the "Hello World" program used in part 1.  However, after seeing that you still didn't have any idea how to program in Java.  Well, you are probably in the same boat here.  That is, you have now seen a leJOS program, but you still don't know how to program with leJOS.  Fortunately, leJOS is written on top of the Java language, so getting up to speed in leJOS shouldn't take much if you already know Java.  In this portion of the lab we will take a closer look another application using the leJOS API and discuss some of its fundamental concepts.  In order to complete this part of the lab, it is recommended that you have the RoverBot from last week built.  At the very least, you should have your RCX connected to a motor via a cable mounted on port A.

Effectors/Motors

There are three Motors already defined in leJOS and stored as static variables These are controlled using:

Consider the following leJOS application.  (You may want to copy and paste this into an editor such as jGrasp or Edit so that you can actually compile and download this onto your RCX).


            import josx.platform.rcx.*;

            //////////////////////////////////////
            /**
            * Represents a simple sample application.
            *
            * @author The leJOS Tutorial
            * @version 1.0 
            */
            public class SimpleSample {        

                ////////////////////////////////////////////
                // public methods
                ////////////////////////////////////////////

                ////////////////////////////////////////////
                /**
                 * main method 
                 * @throws InterruptedException
                 */
                public static void main(String[] args) 
                    throws InterruptedException {

                    TextLCD.print("DRIVE");
                    Motor.A.forward();
                    Motor.C.forward();

                    // just run until RUN button is pressed again
                    Button.RUN.waitForPressAndRelease();

                } 

            } 
        

The import statement


            import josx.platform.rcx.*;
        

The basic package, which contains most of the essential leJOS classes, is josx.platform.rcx. The name is somewhat due to historical reasons, for Jose Solarzano was the inventor and first developer of leJOS. For an overview of this package consult the leJOS API.

The entry point: main()


        public static void main(String[] args) 
                    throws InterruptedException {
        

As with most Java applications, the entry point of a lejos program is the main() method. In our case, it throws an InterruptedException arising eventually from the Button.RUN.waitForPressAndRelease() call below.  What will happen when such an exception occurs?  The RCX will stop the execution of the main() method and display some (rather cryptic) error information on its LCD. You should not concern yourself about the details of these exceptions at this time.

Output


        TextLCD.print("DRIVE");
        

You might have noticed that the graphical user interface of the RCX is rather limited - in fact, there's only the little LCD in its middle for such a purpose.  Worse yet, it is limited to writing up to only five numbers or letters to the LCD using the static methods of the TextLCD or the LCD class.   Thus the abilities of a leJOS program for visual output are quite weak (compared to Java applications running on a PC) - a fact that makes debugging in leJOS a somewhat challenging task.  However, it is worth pointing out that you can get at least simple messages out to the user using only the RCX brick.

There ARE mechanisms, though, to display graphical information to the user: you might transfer information to the IR tower using the IR sensor in front of the RCX and display it on your PC's screen. However, this is a more advanced feature - see the specialized trail on communication contained in this tutorial.

You already might have noticed two things of importance here:

  1. You can use the well-known java.lang.String class in leJOS.
  2. You use static methods of TextLCD. This is a major concept of leJOS: The classes which are directly connected to the actual RCX hardware parts - e.g. motors, sensors, buttons or the LCD - are designed to be static ones. As a result you never will construct any of these but just use the methods of the existing single instance.

Running a motor


        // drive forward
        Motor.A.forward();
        

This piece of code runs the motor connected to the RCX's port A in "forward" mode (the direction the motor actually spins depends on the orientation in which you mounted the connector).

Again note that you use a static instance of the Motor class - to be more precise, a static member (named A) of this class, which refers to "motor connected to port A". As you might have already guessed, the two other motors are referred to as Motor.B and Motor.C, respectively.  If the motor in question is connected to some wheel assembly accurately, your robot will now drive forward.

Keep on running


        // just run until RUN button is pressed again
        Button.RUN.waitForPressAndRelease();
        

So, what's the use of this? you might be tempted to ask at this point of time, Isn't my robot running yet?.
The answer is: yes AND no.
Let's take a look at the program and assume the last statement would be missing:

  1. The motor is running now and the Motor.forward() method returns immediately, so the program moves to the next statement.
  2. But there is none, so main() comes to an end and returns control to the operating system, which terminates program execution (for there is no thread left to be executed).
  3. This results, among others, in the motor stopping.
  4. Thus, the effect of the missing Button.RUN.waitForPressAndRelease() statement is the motor running for a very short period of time (maybe not noticeable at all, leaving behind a staggered user) and stopping right away.

Regarding this we have to assure that program execution doesn't stop or a least at the point of time we choose it to.
As always, there are many ways to accomplish this task. One of the simplest ones, though, is to force the program waiting for the user pressing and releasing the RUN button which is easily got by Button.RUN.waitForPressAndRelease().


Sensors

Just as there were pre-defined motor constants, there are pre-defined sensors

In most cases, when you go to use a Sensor you must “set type and mode” in order to use a sensor.

setTypeAndMode(int aType, int aMode)

Where

For example, if you want to use a boolean touch sensor you would initialize:

Sensor.S1.setTypeAndMode(1,0x20);


However, you may want to read up on the SensorConstants class/interface.  You might argue that the following is easier to read from a code point of view:

Sensor.S1.setTypeAndMode( SensorConstants.SENSOR_TYPE_TOUCH, SensorConstants.SENSOR_MODE_BOOL);


Once you have done this, you can write things like:

Buttons and leJOS

All buttons may be re-programmed except the “on/off” button.   They are either controlled by the Button class (the SimpleSample above) or use event driving programming and Listeners (remember those in CS II?)

public class MyButtonListener implements ButtonListener {
    public void buttonPressed(Button b) {
        //do something?
    }
 

    public void buttonReleased(Button b) {
        //do something?
    }
}

//to use
Button.RUN.addButtonListener(myButtonListener);

 

 


Finding out more about leJOS classes

We have demonstrated only a few of the classes available using the leJOS API.  However, there are a whole wealth of classes that you may use during the course of this semester.  You will most likely want to make sure that you bookmark and frequently refer to the official leJOS API.  There is also a copy of this stored locally on each computer  With this site alone, you should be able to complete any task asked of you this semester.


Prior to attempting the specifics of this assignment you should make sure that you have completed the sections on installing leJOS on your RCX, and learning about the body of a program using leJOS.  Once you have done so, it is time to dive in head first and see if you can figure out how to perform a simple task with your RoverBot from last week.

Specifics

Your task this week is to program your RoverBot from last week so that it moves about its environment performing obstacle avoidance maneuvers when necessary.  You will likely find that the finished program is short and simple in hind sight, but given your current knowledge of leJOS, I anticipate this may be a reasonable enough challenge for this week. 

Using HelloWorld.java and SimpleSample.java as references, write a simple "main" class called ObjectAvoider.java.  Upon downloading the binary for this class onto your RCX and pressing the RUN button, the program should cause your RoverBot to proceed in a straight line until it interacts with an obstacle.  How will you know that you have interacted with an obstacle?  You were to build a double-bumper last week which uses two touch sensors.  Check out the leJOS API to figure out how to either poll your touch sensors, or have them send an "interrupt" when pressed. 

Once an obstacle is detected, your RoverBot should attempt an avoidance maneuver.  The simplest maneuver, and the one I would like you to use, is to back up, rotate away from the object, and then proceed again.

Your robot should continue "roving" and avoiding until the program is "terminated" by a human user.

Deliverables

By the due date and time, submit the files:

via the electronic submission system.  You will also need to prepare your documentation packet following the homework collection policies.


Portions of this lab modified from an excellent tutorial for leJOS by Matthias Paul Scholz available at
http://lejos.sourceforge.net/tutorial/