Saturday, January 3, 2009

Monte Carlo Localization of Robots

In this and future blog entries, I want to discuss my current project with the NXT. I want to develop a program, written in Java, which demonstrates the concept of Monte Carlo robot localization (MCL). For now, I’ll defer any discussion about MCL to another blog entry. However, for those of you who want to read about MCL now, please read the paper by Dellaert, Fox, Burgard, and Thrun.

The problem with demonstrating MCL to a group of students is that the program cannot be run locally on the NXT brick itself. True, the students will be able to see my robot moving around, but they will not be able to understand how the MCL program works.

In my project, the MCL algorithm will be implemented on a PC, which has Bluetooth capability. Using Bluetooth, the PC will send commands to the robot. In response to these commands, the robot, which also has Bluetooth capability, will perform the action -- such as move forward, move backward, turn left, turn right -- and then send back to the PC the reading from the robot’s only sensor, the ultrasonic sensor.

Using the reading from the ultrasonic sensor together with a map of the walls of the enclosure in which the robot is found, the PC will try to localize the robot; i.e. determine its position within the enclosure.

The most challenging part of the project is actually the development of the graphical user interface (GUI). We cannot be content to use the RConsole class as mentioned in my January 1st blog entry. RConsole is too primitive. What we want and need is a professional and attractive display of the current state of the MCL algorithm.

In Java, the main window is called a JFrame. Every JFrame consists of a number of JPanels. Every JPanel consists of a number of Components. Components are such things as buttons, labels, text boxes, sliders, spinners, progress bars, radio buttons, check boxes and other such widgets commonly found on GUIs.

The idea behind this project is that we will define a series of JPanels. Another class, to be defined later, will instantiate each of these JPanels and arrange them in a JFrame, which will act as our project’s GUI.

For our GUI, we’re going to need four panels: a connection panel for handling the Bluetooth connection; a command panel for issuing commands to the robot; a statistics panel for collecting and displaying sensor readings from the robot; and a display panel for displaying the current state of the MCL algorithm. In this blog entry, we’ll focus on the statistics panel.

Before coding the statistics panel, we must consider that every panel can fire what Java calls action events. These action events fire, usually, in response to clicks on buttons, moving a slider, or changing the value of a spinner to name a few examples. We need a mechanism to capture these action events and respond appropriately to them. If we do not listen for these action events, our GUI will be unresponsive and useless to the user.

Unlike my blog entry of January 2nd, we do not want each panel to handle its own events through the use of the code addActionListener(this);. Otherwise, our action event handling code will be spread over several classes making our code very difficult to maintain. Instead, we want a single class to centrally handle all of the action events for all of the panels. The event handler class is:

package local;

import java.awt.event.*;

public class EventHandler implements ActionListener {

public void actionPerformed(ActionEvent e){

}

}

For now, the actionPerformed method has an empty implementation, which we will fill in as we need to code up the steps the EventHandler should take in response to the various action events sent to it by the various panels. Whenever an action event is fired, the actionPerformed method will be called to handle the action event.

However, each panel will need a reference to the EventHandler as instantiated by the class responsible for assembling the JFrame together. This is accomplished by defining each panel’s constructor as public panelName(EventHandler eventH){code}. In other words, for a panel to be instantiated, the panel must be passed a reference to the EventHandler. The class responsible for assembling the JFrame would do something like this:

EventHandler eventHndl = new EventHandler();
Statistics statsPanel = new Statistics(eventHndl);

We want the statistics panel to show the battery voltage and the ultrasonic sensor readings as vertical progress bars. We want the first echo from the ultrasonic sensor to appear in a textbox as a numerical value. We want two buttons: one button to call for the battery voltage and a second button to manually cause the ultrasonic sensor to be pinged and the result displayed on the GUI. The panel should look like this:



The code at the end of this blog entry is meant to be run on your PC. Consequently you should not change your project into a Lejos project. The main method can be called to display the panel, but it must be borne in mind that this main method is strictly for testing and debugging purposes. The real main method will appear in another class. In practice, the main method of the Statistics class will never be run.

Note that the Statistics class extends JPanel --- not JFrame. This is important. Many examples of GUIs given in web tutorials show classes extending JFrame, because these examples typically involve components being added directly to the JFrame. While this approach is fine in simple applications, it is difficult to use when the GUI becomes complex. So, we are not taking that approach here. Components are being added to each JPanel, and each JPanel is being added to a single JFrame.

Finally, the Statistics class owns its components in the sense that its components are private. The state of components can only be changed by users of the panel through the class’s set methods; the values stored in the components can only be accessed through the class's get methods. This approach ensures that the correct data types are used when passing data to and from the JPanel. This approach also prevents the user of the class from changing the state of components that should not be changed; i.e. components like text labels that are purely decorative in nature.

If you wish to see the panel with the two buttons in the active state, add this line of code to the main method.

statsPanel.setButtonsEnabled(true);

The next time I blog, I will discuss the connection panel, the second panel which makes up the four panels of our GUI. If you have any questions, please do not hesitate to contact me. The code for the Statistics class can be found here.

2 comments:

Marco A. A. de Oliveira said...

Greetings,

Thank you for a very interesting post/article.

I would like to suggest that your reference text citing Dellaert etal. be corrected regarding Thrun (i.e., Thrun vs. Thurn).

Regards,

Marco A. A. de Oliveira
ma2oliveira@gmail.com

Unknown said...

Thank you my friend for your most welcome suggestion for improvement in my spelling. I have made the correction.