Monday, March 24, 2014

Controlling NXT Robot From the Keyboard with leJOS NXJ

Bad GUI for robot control
(UPDATE: So this was all well and good as a proof of concept but we found when we brought the motors into the mix the motors were too slow to respond to direct commands. We learned a lot in the process, though.)

I worked up a proof of concept in leJOS NXJ I'll be teaching my high school robotics students soon for a method of controlling a
tethered NXT robot directly through key presses. At first I had worked out a GUI with buttons following some Head First Java lessons but I realized that wasn't an optimal way to control a robot, by moving a mouse around clicking it. Arrow keys make much more sense. Capturing arrow key presses was hard to figure out. The Scanner class won't do because you type in a line and your String is captured when enter is pressed. For instant capture of every key press a KeyListener is needed, or that's the simplest way I could figure out.
So the solution I worked out is a text field with a KeyListener, and each arrow key press event calls a send-over-USB class method, sending a number over a data stream to the robot, which responds to the number sent with motor commands. In this proof of concept all I'm getting the robot to do is display response text on the LCD but it's a short step from there to driving it around.
Better GUI for robot control
First, the KeyListener GUI: For this I'm indebted to an Oracle example on KeyListeners. I stripped everything out that I didn't need in order to learn the bare elements that were needed. Here is the KeyEventDemo.java class, in plain text.
Second, the Sender class: There is an example in the leJOS NXJ download that sets up a data stream between PC and NXT over USB. This opens a data stream, sends an int 100 times to a Receiver class, receives it back from the NXT, and closes the data stream. I needed the data stream to stay open as long as the user wants to send new commands. The way the USB send examples were originally written, every time a key was pressed a whole new connection was established, and read and write data streams opened, which made each key press take 7-10 seconds to reach the NXT. So I moved the connection into the USBSend constructor so it would be established as soon as the USBSend class was referenced, then it was just the data streams that were opened and closed each loop. Synchronizing the logical coordination of opening and closing the streams and the connection was tricky to figure out. The other thing to figure out was how to close the IO streams and USB connection gracefully at the user request, which worked out nicely in the USBReceive class.
Here's the adapted USBSend.java class.
And the USBReceive.java class.
A few things that are helpful to know with leJOS.
  • the KeyEventDemo and USBSend classes have to be set up as a PC project, while the USBReceive class is a leJOS project.
  • On Mac with anything Snow Leopard + PC classes have to be run in 32 bit mode. In Eclipse you open run configurations and add -d32 to the VM arguments.

No comments :