A very big question about using computer to controll a robot

Hay and I apologize for the bomb I am about to drop…
I want to make a robot that will recognize voice commands and that will be able to compare 2 pictures and to determine if they are alike or not. The pictures don’t have to be similar only alike.
So I will need a photo recognizing program of some sort and some thing that will recognize voice commands.

My other question is how do I work a robot throe the computer? I know that I will have to use the serial port, but what is the programming language that I have to use? is there a program that will transfer the code to the robot? how do I use sensors and how do I activate motors (both servos and DC).

I am using ubuntu 8.04

Thanks
Arbel

You’re right, those are some HUGE questions, and there are about a million different approaches, or make that a million and one. I just saw a neat demo by some guys from RoadNarrows Robotics of something called Recognetics (they have it here, manufacturer here). I don’t pretend to know how it works, but they’re calling it a neural network chip (sounds really cool, doesn’t it) for data recognition from any kind of sensor (video, audio, etc…).

What I can tell you about it is that they hooked it up to a little camera facing a picture of Homer Simpson, and had it associate that image with a Simpson’s movie quote mp3, which it triggered on a laptop. At this point the chip had nothing to compare Homer to, so it thought everything was Homer Simpson, and kept looping the mp3. Then they showed it a picture of Indiana Jones and associated that with an Indy quote (“Snakes…why did it have to be snakes?”). Sure enough, it could tell the two apart, and played the appropriate mp3’s. As it only “knew” two things at this point, it had the interesting tendency to classify images of other objects (i.e. my hand) as either Homer or Indy.

With a little training it seems like it would be very good at recognizing and categorizing similar, but not necessarily identical things. The really neat part is that it’s just doing general data recognition, not specific image processing techniques, so you could use it to process other kinds of data, like audio, or radar for that matter. I have no clue how much it costs or how hard it is to set up or interface with, but it sure was neat.

-Adam

P.S. You’ll probably need some special hardware (like a serial adapter kit USB to Serial Adapter) to connect your computer and your robot, but you should be able to talk to a serial port with just about any programming language, do you have any favorites? I’ll have to let someone better versed in the ways of Linux handle the specifics though.

O.K, first thing first,
how do I use the serial adapter? how do I connect it to the orangutan, and how do I run the program and how do I connect the sensors and the motors? there is no data on the site…
Arbel

The ATMega168’s USART hardware (which you used before to communicate between your Orangutan and Baby Orangutan) uses a serial protocol very similar to the RS-232 protocol that the 9-pin serial port in the back of your computer uses, but the polarity and voltages involved are very different, and connecting a serial port directly to your microcontroller would damage it!

There are some tricky techniques for converting signals between the two devices, but if you want easy two-way communication with a computer’s 9-pin serial port you should get something like the Pololu serial adapter. It basically flips the polarity of the serial signals going in each direction, and limits the voltage to the safe 0V-5V range on the microcontroller side. It also uses a neat trick with capacitors to generate the +/- 12V signals the computer serial port uses. For a basic connection all you need is a straight-through DB9 serial extension cable (you can scrounge one up, or buy one from Pololu) to connect the adapter to your computer, and to connect the adapter’s TX line to the ATMega’s RX (PD0), and the adapter’s RX to the ATMega’s TX (PD1), and the adapter and ATMega’s grounds together.

If your computer doesn’t have a 9-pin serial port (sadly they’re becoming less and less common) or you would just rather use a USB port, you can use something like the Pololu USB to Serial adapter instead. It plugs in with a USB A to Mini-B cable (again, also available from Pololu, and crammed in the back of desk-drawers everywhere), but after you install its drivers it will look to any software on your computer like any other serial port. For basic use you will need to make the same three connections.

Beyond that, communication between your computer and your Orangutan is a matter of selecting the specific parameters of your serial protocol (by far the most common is 9600 bps, 8-bytes per bit, no parity, one stop bit), configuring the USART by setting registers on your ATMega just like you did before for Orangutan to Orangutan communication, and writing software to transmit and receive bytes on your computer. Each byte is an eight-bit number (from 0 to 255), and what these bytes mean and how they are interpreted (i.e. sensor states or motor commands) is up to you. How to send/receive serial bytes from a particular computer is a matter of your operating system and selected programming language. I know of a couple of ways to do this that specifically use the Windows API, but I don’t have any experience doing this in Linux.

What’s your favorite computer programming language (c? java? python? even would matlab would work)? There is surely a way to use it to talk to a serial port.

-Adam

I think I’ll go with C or basic.
So I will need to write a program that will recive the bytes from the orangutan and then translate that in to an event in the computer? for example: when a sensor is pressed on the robot, the computer will show a smiling face…
how do i do that? how do I get the bytesfrom the orangutan and translate them???
Is there program that I can see to lern from?
Arbel

Pololu sample project 3 includes example C code (ssc.c, ssc.h) for writing bytes to a serial port in Linux. It includes headers for all the libraries you should need for two-way serial communication, but this particular example only uses the “write” command.

I did a little poking around online for Linux code examples, and I think to add a function to this example project that would read a string of bytes waiting in the serial port buffer you would use something like this:

int res;
char buf[6];
res=read(s->fd,buf,5);
buf[res]=0;

This code snippet is asking to read the next five characters available in the serial buffer into a six-byte character array “buff”. “res” is a counter of the number of bytes actually read (up to 5), and the last line adds a string termination character 0 to the end of the data actually read.

For this to work, I think you will also need to change the line:
s->fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
in the example code to
s->fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NONBLOCK);

If I’m reading things right, the 0_NONBLOCK property will make the read function return immediately with however many bytes are already waiting in your serial buffer to be read (up to the requested number, in this case 5). If you don’t make this change, I think the read function will wait until the requested number of bytes arrive. If you want you can do it that way too. Sorry I don’t have more definite answers for you, like I said, I’m not super Linux guy.

-Adam

P.S. If this doesn’t do it, you might want to post a more specific question under the Linux Software topic, and/or search for Linux+C serial port tutorials.

I am afraid that I am steel at the basics… I didn’t understand how do I send information to the orangutan, and how dose that information looks like (do I send 01001110 or something else?). So, let’s go back a bit…
all I would like to do now is to activate 1 DC motor forward when I press i button in a program and then to make that motor go back when I press the second button.
how do I do that? forget about the linux part. how would you do that in XP?
thanks
Arbel

In Windows I would write a C program that looked something like this:

/*Serial Control Test Program for Windows
V 1.0
Adam Borrell
5/27/08*/

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>

//Function Prototypes
HANDLE openPort(int);
HANDLE comPort;

//Global Variables
int done=0;
DWORD len;
unsigned char buff[1];

int main(){
	char input[32];
	int i;
	
	printf("Pololu Serial Servo Controller Test Program\n\n");
	
	comPort=openPort(1);//***PUT YOUR COM PORT NUMBER HERE!***
	if(done){
		printf("Program Terminated!\n");
		system("PAUSE");
		return -1;
	}
	
	printf("Commmands:\n");
	printf("F - Forward\n");
	printf("R - Reverse\n");
	printf("S - Stop\n");
	printf("BACKSPACE - Exit\n\n");

	while (!done) {//***Simple keyboard interface
		*input = getch();
		switch(*input){
			case 8://backspace
				done = 1;
				break;
			case'f':
			case'F':
				printf("FORWARD!\n");
				buff[0]=128;
				WriteFile(comPort,&buff,1,&len,0);
				break;
			case'r':
			case'R':
				printf("REVERSE!\n");
				buff[0]=129;
				WriteFile(comPort,&buff,1,&len,0);
				break;
			case's':
			case'S':
				printf("STOP!\n");
				buff[0]=130;
				WriteFile(comPort,&buff,1,&len,0);
				break;
			default:
				break;
		}
	}
	CloseHandle(comPort);
	printf("Program Terminated!\n");
	system("PAUSE");
	return 0;
}

HANDLE openPort(int portnum){
	char port[]="com", pnum[]="Error";
	itoa(portnum,pnum,10);
	strcat(port,pnum);
	
	HANDLE serial=CreateFile(port,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	if(serial==INVALID_HANDLE_VALUE){
		if(GetLastError()==ERROR_FILE_NOT_FOUND){
			printf("Error, %s Not Found\n\a", port);
			done=1;
			return;
		}
		printf("Com Error\n\a");
		done=1;
		return;
	}

	DCB dcbSerialParams={0};
	dcbSerialParams.DCBlength=sizeof(dcbSerialParams);

	if(!GetCommState(serial, &dcbSerialParams)){
		printf("Com State Error\n\a");
		done=1;
		return;
	}

	dcbSerialParams.BaudRate=CBR_9600;//CBR_baudrate
	dcbSerialParams.ByteSize=8;
	dcbSerialParams.Parity=NOPARITY;//NOPARITY, ODDPARITY, EVENPARITY
	dcbSerialParams.StopBits=ONESTOPBIT;//ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS

	if(!SetCommState(serial, &dcbSerialParams)){
		printf("Serial Protocol Error\n\a");
		done=1;
		return;
	}
	
	COMMTIMEOUTS timeouts={0};
	timeouts.ReadIntervalTimeout=50;
	timeouts.ReadTotalTimeoutConstant=50;
	timeouts.ReadTotalTimeoutMultiplier=10;
	timeouts.WriteTotalTimeoutConstant=50;
	timeouts.WriteTotalTimeoutMultiplier=10;

	if(!SetCommTimeouts(serial,&timeouts)){
		printf("Timeout Setting Error\n\a");
		done=1;
		return;
	}
	
	return serial;
}

You can download the source here.

I would also load a code like this onto the Orangutan or Baby Orangutan:

/*Serial Control Test Program for Orangutan or Baby Orangutan
V 1.0
Adam Borrell
5/27/08*/

#define F_CPU 20000000//CPU clock for Baby Orangutan
//#define F_CPU 8000000//CPU clock for Orangutan
//***Uncomment ONE of the above lines for the specific device***

#define BAUD 9600//baud rate for UART
#define MYUBRR (F_CPU/16/BAUD-1)//baud rate variable for UART hardware

#include <avr/io.h>
#include <avr/interrupt.h>

unsigned volatile char dataIn,newSerCmd=0;

void USART_Init(unsigned int ubrr){//Initialize USART hardware & settings for Serial Radio
	UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
	UBRR0L=(unsigned char) ubrr;
	UCSR0B=(1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0);//enable transmitter & receiver, receive complete interrupt
	UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}

ISR(USART_RX_vect){//USART Byte reieved
	dataIn=UDR0;//grab copy of serial byte
	newSerCmd=1;//indicate new byte received
}

int main(){
	DDRB|=(1<<PB1);//setup output pins
	DDRD|=(1<<PD5);

	USART_Init(MYUBRR);//Initialize USART
	sei();//enable global interrupts

	while(1){
		if(newSerCmd){//if new byte received
			switch(dataIn){
				case 128://forward
					PORTB|=(1<<PB1);
					PORTD&=~(1<<PD5);
					break;
				case 129://reverse
					PORTB&=~(1<<PB1);
					PORTD|=(1<<PD5);
					break;
				case 130://stop
					PORTB&=~(1<<PB1);
					PORTD&=~(1<<PD5);
					break;
				default:
					break;
			}
			newSerCmd=0;
		}
	}
	return 0;
}

You can download the source here.

The Windows program opens a com port (at 9600 BPS, 8 data bits, no parity, one stop bit), and when you press the F, R, or S keys (upper or lower case) it sends arbitrarily selected byte values out the com port. When you hit backspace the program closes the com port.

The AVR program configures the hardware USART (again for 9600 BPS, 8 data bits, no parity, one stop bit), and sets up the byte received interrupt. When there is a byte received it checks if it has one of the (arbitrary) values corresponding to the key presses in the Windows program, and takes some action. If you pressed F, it sets one of the motors going forward, if you pressed R it sets that motor backwards, and if you pressed S it stops the motor. On the big Orangutan it’s the right motor port, I’m not sure which motor port it is on the Baby Orangutan. There’s no PWM here, the code is directly manipulating the H-bridge pins.

I just tried both and they work for me. They’re not completely commented, but this code I can really answer questions about. Note that there’s a place in the Windows code to specify your com port number, and a place in the AVR code to specify which Orangutan you’re using (really just what clock speed it’s running at).

-Adam

P.S. You’ll still need a serial adapter of some sort.

So, in the orangutan code, in the switch case part, you wrote the ascii number of F,R and S. and the program at the computer sends that code to the orangutan. And then the orangutan dose something with that information. Am I correct?
My second question, then, is how to receive information from the orangutan to the computer? i.e - if a sensor is pressed, the computer will display something.

O! I think I got it… It’s not the ascii code, you sent those numbers using buff[0]! Am I correct?

Correct, I’m just sending arbitrary numbers that I chose to correspond to the commands. If you want you can pick other numbers, or use the ascii character codes (i.e. buff[0]=‘f’:wink: I started with 128 because the old terminal-style ASCII codes end at 127.

Sending information back the other way is just a little extension of the code I posted yesterday, I’ll try to post a working version later this afternoon. By the way, which Orangutan are you using? What did you have in mind for an event to send something back to the computer? I was thinking a built-in button-press on the big Orangutan.

In the meantime this is a drop-in addition to the AVR code I posted last night, it’s a simple function that will send a byte of serial data:

void USART_Trans(unsigned char data){//Transmit a byte of data over USART while(!(UCSR0A&(1<<UDRE0)));//wait for transmition to complete UDR0=data; }By the way, I copied these serial functions pretty much straight from C examples on the ATMega168 datasheet.

Also this is where I got started with serial port communication using the Windows API.

Happy reading!

-Adam

Thanks but I don’t think I’ll get so much into the windows stuff. I just want to learn from your code how dose that work and how it should look like.
I am trying to make a robot that will be able to take a photo and then send it to the computer and then the computer will compare that photo to a photo data base and then the robot will do something according to the results of the photo compare.
something like that…

In the new code you’v sent, how do I make the Data to contain a sensor’s position? is it exactly like the uart code when connecting 2 orangutans?

I am using atmega168.

It is exactly the same. You can send any 8-bit byte value you want (i.e. numbers from 0 to 255), so what they mean is up to you.

-Adam

Thanks
I ordered the serial adapter a few days ago I hope it will be here soon and then I can get nasty with it!

Adam, in what part of the computer code the program waits for a signal from the orangutan?

No part, yet…

Well yesterday afternoon turned into this morning, but here is some two-way serial communication code, for the Windows computer side:

/*Serial Control Test Program for Windows
V 1.1
Adam Borrell
5/29/08*/

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>

//Function Prototypes
HANDLE openPort(int);
HANDLE comPort;

//Global Variables
int done=0;
DWORD len,dwBytesRead=0;
unsigned char buff[1],inBuff[1];

int main(){
	char input[32];
	int i;
	
	printf("Pololu Serial Servo Controller Test Program\n\n");
	
	comPort=openPort(1);//***PUT YOUR COM PORT NUMBER HERE!***
	if(done){
		printf("Program Terminated!\n");
		system("PAUSE");
		return -1;
	}
	
	printf("Commmands:\n");
	printf("F - Forward\n");
	printf("R - Reverse\n");
	printf("S - Stop\n");
	printf("BACKSPACE - Exit\n\n");

	while (!done) {//***Simple keyboard interface
		if(kbhit()){
			*input = getch();
			switch(*input){
				case 8://backspace
					done = 1;
					break;
				case'f':
				case'F':
					printf("FORWARD!\n");
					buff[0]=128;
					WriteFile(comPort,&buff,1,&len,0);
					break;
				case'r':
				case'R':
					printf("REVERSE!\n");
					buff[0]=129;
					WriteFile(comPort,&buff,1,&len,0);
					break;
				case's':
				case'S':
					printf("STOP!\n");
					buff[0]=130;
					WriteFile(comPort,&buff,1,&len,0);
					break;
				default:
					break;
			}
		}
		ReadFile(comPort,inBuff,1,&dwBytesRead,0);
		if(dwBytesRead){
			if(inBuff[0]==131){
				printf("BUTTON PRESSED!\n");	
			}	
		}
	}
	CloseHandle(comPort);
	printf("Program Terminated!\n");
	system("PAUSE");
	return 0;
}

HANDLE openPort(int portnum){
	char port[]="com", pnum[]="Error";
	itoa(portnum,pnum,10);
	strcat(port,pnum);
	
	HANDLE serial=CreateFile(port,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
	if(serial==INVALID_HANDLE_VALUE){
		if(GetLastError()==ERROR_FILE_NOT_FOUND){
			printf("Error, %s Not Found\n\a", port);
			done=1;
			return;
		}
		printf("Com Error\n\a");
		done=1;
		return;
	}

	DCB dcbSerialParams={0};
	dcbSerialParams.DCBlength=sizeof(dcbSerialParams);

	if(!GetCommState(serial, &dcbSerialParams)){
		printf("Com State Error\n\a");
		done=1;
		return;
	}

	dcbSerialParams.BaudRate=CBR_9600;//CBR_baudrate
	dcbSerialParams.ByteSize=8;
	dcbSerialParams.Parity=NOPARITY;//NOPARITY, ODDPARITY, EVENPARITY
	dcbSerialParams.StopBits=ONESTOPBIT;//ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS

	if(!SetCommState(serial, &dcbSerialParams)){
		printf("Serial Protocol Error\n\a");
		done=1;
		return;
	}
	
	COMMTIMEOUTS timeouts={0};
	timeouts.ReadIntervalTimeout=1;
	timeouts.ReadTotalTimeoutConstant=1;
	timeouts.ReadTotalTimeoutMultiplier=5;
	timeouts.WriteTotalTimeoutConstant=1;
	timeouts.WriteTotalTimeoutMultiplier=5;

	if(!SetCommTimeouts(serial,&timeouts)){
		printf("Timeout Setting Error\n\a");
		done=1;
		return;
	}
	
	return serial;
}

Or download the source here.

And for the Orangutan side:

/*Serial Control Test Program for Orangutan or Baby Orangutan
V 1.1
Adam Borrell
5/29/08*/

//#define F_CPU 20000000//CPU clock for Baby Orangutan
#define F_CPU 8000000//CPU clock for Orangutan
//***Uncomment ONE of the above lines for the specific device***

#define BAUD 9600//baud rate for UART
#define MYUBRR (F_CPU/16/BAUD-1)//baud rate variable for UART hardware

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

unsigned volatile char dataIn,newSerCmd=0,wasPressedAlready=0;

void USART_Init(unsigned int ubrr){//Initialize USART hardware & settings for Serial Radio
	UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
	UBRR0L=(unsigned char) ubrr;
	UCSR0B=(1<<TXEN0)|(1<<RXEN0)|(1<<RXCIE0);//enable transmitter & receiver, receive complete interrupt
	UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}

void USART_Trans(unsigned char data){//Transmit a byte of data over USART
   while(!(UCSR0A&(1<<UDRE0)));//wait for transmition to complete
   UDR0=data;
}

ISR(USART_RX_vect){//USART Byte reieved
	dataIn=UDR0;//grab copy of serial byte
	newSerCmd=1;//indicate new byte received
}

int main(){
	DDRB|=(1<<PB1);//setup output pins
	DDRD|=(1<<PD5);

	USART_Init(MYUBRR);//Initialize USART
	sei();//enable global interrupts

	while(1){
		if(newSerCmd){//if new byte received
			switch(dataIn){
				case 128://forward
					PORTB|=(1<<PB1);
					PORTD&=~(1<<PD5);
					break;
				case 129://reverse
					PORTB&=~(1<<PB1);
					PORTD|=(1<<PD5);
					break;
				case 130://stop
					PORTB&=~(1<<PB1);
					PORTD&=~(1<<PD5);
					break;
				default:
					break;
			}
			newSerCmd=0;
		}

		if((PINB&((1<<PB3)|(1<<PB4)|(1<<PB5)))){
			if(!wasPressedAlready){
				USART_Trans(131);//transmit byte
				wasPressedAlready=1;
			}
		}else if(wasPressedAlready){
			wasPressedAlready=0;
			_delay_ms(10);//debounce delay
		}
	}
	return 0;
}

Or download the source here.

This program pair has the functionality of the previous version, and now when you press one of the Orangutan’s three built-in buttons (or bring PB3, PB4, or PB5 high on a Baby Orangutan) you should see the message “BUTTON PRESSED!” in the terminal window on your computer. Since this code makes use of the Orangutan’s buttons I uncommented the 8MHz clock definition, but it will work on either O.

-Adam