Controlling Orangutan X2 from a Laptop USB port

Dear Forum Members,

I got my Orangutan X2 recently and I have been playing around with it. I love it.

So far, I have built a robot platform where I understand how to control the motors, read input from Port A, D etc., Fine and dandy. I want to kick it a notch and add some interesting features by letting a laptop control my Orangutan X2. I am aware that the ATMEGA168 in X2 can work with a laptop in the normal mode and accept commands. But I have not found any samples or procedure on how to do it.

I am intending to do the following:

  1. Have my laptop control the motors through the X2 board and let X2 board communicate the interrupts like Range Sensor inputs / limit switch inputs / Optical Encoder inputs etc.,
  2. Add a Video camera and do some pattern recognition and again control the robot platform through X2 board in real-time
  3. Add voice commands support through the laptop and again control the robot platform through X2 board in real-time.

I am basically looking for examples for bi-directional control of X2 board from a laptop.

Can you kindly point me to any sample projects / code /suggestions for software packages etc., for each of the above features (1,2,3)?

Your help much appreciated.

Cheers,

Hello.

Unfortunately I don’t know of any existing code examples of what you’re looking for, but I can give you some information that might help. The X2’s auxiliary microcontroller (the mega168) handles the UART interface with the CP2102 USB-to-UART bridge; there are a series of commands you can send to the mega168 from the mega644 to use the UART. You can find a low-level description of these commands here:

pololu.com/docs/0J9?section=3.c

Our SPI wrapper functions give you high-level C functions you can call from the mega644 to use the UART. The following untested code can hopefully serve as an example of how you can use the UART (make sure you have added SPI.c to your AVR Studio project):

#include <avr/io.h>
#include "SPI.h"

int main()
{
    SPIInit();    // configure SPI hardware for communication with the mega168

    // configure the UART for no parity, one stop bit, normal speed, 115.2 kbps baud
    setSerial( UART_NO_PARITY, UART_ONE_STOP_BIT, UART_NORMAL_SPEED, UBRR_115200_BAUD );

    // transmit the string "hello"
    sendSerial( 'H' );
    sendSerial( 'e' );
    sendSerial( 'l' );
    sendSerial( 'l' );
    sendSerial( 'o' );

    while (1)
    {
        // wait here until the UART receives a byte
        waitUntilUARTReadReady();

        // read the byte, which removes it from the read buffer
        unsigned char value = readSerial();

        // just for fun, make the buzzer play a note based on the received value
        //  i.e. turn your keyboard into a "piano"
        playNote(value - 32, 200);
    }

    return 0;
}

I don’t have an X2 with me right now, so I can’t see if this actually works, but at least it compiles! If you plug your X2 into your laptop’s USB, start up a terminal program like Hyperterm, and connect to the X2’s COM port at 115,200 bps (8 characters, no parity, one stop bit), you should see “Hello” appear in your terminal when you reset the X2, and you should hear notes play when you type characters into your terminal.

Once you’re comfortable sending and receiving bytes over the UART, controlling your X2 from your laptop simply becomes a matter of your inventing a command protocol and programming your X2 to respond to that protocol. For example, you could program your X2 to wait for input from your laptop, and that input is the byte sequence [ 0x80, 0x01, 0x25 ], call setMotor1(0x25). Just make sure that your protocol is robust enough to allow you to gracefully deal with lost or corrupted bytes. For example, require that each command packet starts with a byte that can never appear anywhere else in that command’s byte sequence. Does this make sense?

- Ben

Hey Ben,

Thanks for the fast response. I compiled the program and loaded my X2 with it. My Hyperterminal says it is connected with the parameters you sent. But, when I reset X2, I do not see any ‘Hello’ string in the Hyperterminal. Also Hyperterminal screen did not accecpt any characters from my keyboard as well.

I do not believe, the communication with UART is set.

Cheers,

Hmm, I’ll try it out tomorrow when I get to work. Are you sure you’re connected to the right COM port?

- Ben

Ben to the rescue again!

Ben, I was mistaken and I thought I was using COM1 while my COM5 port is the correct one.

Your program worked fine. I rigged it to control my motors.

Cheers,

Alright, got tired of HyperTerminal to test the bi-directional UART communication. I poked around to find out programmatic ways for serial communication. I was successful in my attempt!

Time to give back to the community folks here. I was elated to find easier ways to now interface the Orangutan X2. Yeah, through Java :smiley:

The following Java program is a simple multi-threaded event based reader that listens to the “COM5” port at 115200, 8, None and 1 Stop Bit. Please make sure you compile and program X2 board with the program posted by Ben that sends “Hello” when you press Reset button on the board.

Code Sample details: (For the Java enthusiasts :slight_smile: )
The java code uses the RxTx library (rxtx.org/) which is an implementation of the javax.comm specification. See the import gnu.io.* line in the code. You can extend this program and you can use myriad open source java libraries (voice, opencv etc., ) to creatively interact with your Orangutan X2. Search for “SimpleWrite” in the web to look for code for writing to Orangutan X2.

Good Luck!!!

/*
 * @(#)SimpleRead.java	1.12 98/06/25 SMI
 * 
 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * 
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license
 * to use, modify and redistribute this software in source and binary
 * code form, provided that i) this copyright notice and license appear
 * on all copies of the software; and ii) Licensee does not utilize the
 * software in a manner which is disparaging to Sun.
 * 
 * This software is provided "AS IS," without a warranty of any kind.
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND
 * ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE
 * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS
 * BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES,
 * HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING
 * OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * This software is not designed or intended for use in on-line control
 * of aircraft, air traffic, aircraft navigation or aircraft
 * communications; or in the design, construction, operation or
 * maintenance of any nuclear facility. Licensee represents and
 * warrants that it will not use or redistribute the Software for such
 * purposes.
 */
import java.io.*;
import java.util.*;
import gnu.io.*;

public class SimpleRead implements Runnable, SerialPortEventListener {
    static CommPortIdentifier portId;
    static Enumeration	      portList;
    InputStream		      inputStream;
    SerialPort		      serialPort;
    Thread		      readThread;
    
    public SimpleRead() {
    	try {
    	    serialPort = (SerialPort) portId.open("OrangutanX2", 2000);
    	} catch (PortInUseException e) {}
    	try {
    	    inputStream = serialPort.getInputStream();
    	} catch (IOException e) {}
    	try {
    	    serialPort.addEventListener(this);
    	} catch (TooManyListenersException e) {}
    	serialPort.notifyOnDataAvailable(true);
    	try {
    	    serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8, 
    					   					SerialPort.STOPBITS_1, 
    					   					SerialPort.PARITY_NONE);
    	} catch (UnsupportedCommOperationException e) {}
    	readThread = new Thread(this);
    	readThread.start();
    }
    
    public void run() {
    	try {
    		Thread.sleep(20000);
    	} catch (InterruptedException e) {}
    } 

    public void serialEvent(SerialPortEvent event) {
		switch (event.getEventType()) {	
			case SerialPortEvent.BI:	
			case SerialPortEvent.OE:	
			case SerialPortEvent.FE:	
			case SerialPortEvent.PE:	
			case SerialPortEvent.CD:	
			case SerialPortEvent.CTS:	
			case SerialPortEvent.DSR:	
			case SerialPortEvent.RI:	
			case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
			    break;	
			case SerialPortEvent.DATA_AVAILABLE:
			    byte[] readBuffer = new byte[5];	
			    try {
					while (inputStream.available() > 0) {
					    int numBytes = inputStream.read(readBuffer);
					} 	
					System.out.print(new String(readBuffer));
			    } catch (IOException e) {}	
			    break;
		}
	} 

    public static void main(String[] args) {
	    boolean		      portFound = false;
	    String		      defaultPort = "COM5";
	 	if (args.length > 0) {
		    defaultPort = args[0];
		}    
		portList = CommPortIdentifier.getPortIdentifiers();	
		while (portList.hasMoreElements()) {
		    portId = (CommPortIdentifier) portList.nextElement();
		    if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
				if (portId.getName().equals(defaultPort)) {
				    System.out.println("Found port: "+defaultPort);
				    portFound = true;
				    SimpleRead reader = new SimpleRead();
				} 
		    } 
		} 
		if (!portFound) {
		    System.out.println("port " + defaultPort + " not found.");
		} 
	} 
}

To Compile and Run:
Use Eclipse or your choice of IDE (skipping details) and compile SimpleRead.java

Run SimpleRead which listens to Serial communication from X2.
You will see the following output:

Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7

Now press the Reset button in the Orangutan X2 board. You will see:

Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
Hello

Enjoy!!!

Cheers,

I’m glad to hear everything is working. Thanks for the code!