jump to navigation

Adding Infrared Distance Sensors to an AVR Atmega32 04/16/2009

Posted by aliasmrjones in The Build.

After the test run on the actual race course, it was clear that GPS was not going to be accurate enough to keep the car out of the pond.  I tried sonar, which is great for general obstacle avoidance because it will detect basically anything in a 45 degree cone, but it didn’t work well for this specific case.  Infrared distance sensors turned out to be perfect, but I had one other problem to overcome.

I connected this sonar to the i2c bus I was already using for the compass.  One of the cool things about i2c is you can connect many devices to just 2 wires on the microcontroller and communicate with each device based on its address.  I was getting distance readings in inches and it was perfect down to 1″ distance.  Max range was about 4 feet.

Unfortunately, the 45 degree cone of the sonar is both left and right and up and down.  When I put the sonar on the car, it was detecting the ground.  I tried tilting it up and I even tried building a shield to block the sonar reflections from the ground.

Sonar Shield

Sonar Shield

The shield extended the range of the sonar, but it still had trouble detecting the curb and the car couldn’t turn fast enough to avoid objects.  The range was only 18-24″ being so low to the ground and by the time the car turned the wheels, it had already hit the object.  I decided sonar wasn’t going to work.

The other option for object detection (other than a $3,000 laser, which I felt violated the spirit of the competition) is infrared.  I’ve used ir detectors in the past, and they are very accurate, but usually don’t have the range of sonar and they detect objects in a straight, pencil beam line.  The main obstacle to avoid in the race is the curb, which is a linear obstacle extending out basically to infinity so the almost laser-like detection probably won’t be a problem for the race.  I found some newer, long-range ir sensors I hadn’t seen before.  The Sharp GP2Y0A710YK0F ir sensor claims to detect objects from 40″ to 200″.

I bought a couple and did some testing.  I was getting maybe 4-5 feet of real-world range and putting it right next to the ground was no problem since the ir light beam is so narrow.  Now for the problem.  I needed a full 8 bit port for the LCD and the only port I wasn’t using at least one pin in was port A, the port that has all the analog-to-digital conversion pins.  The ir sensor outputs an analog voltage, higher voltage means close object.  So, my choices were to try to totally rewire the LCD (14 wires – ugh) or figure out another way to connect the sensors.

I had a spare Atmega8 laying around and I knew AVRs could be i2c slaves as well as master so I decided to try to program the Atmega8 to read the sensors and report back the analog voltage values to the main chip through i2c.  I initially had some problems, but was eventually able to get it working using AVRLib.  Here is the code in the Atmega8 to read the Sharp ir distance sensors:

DDRC = 0x00; //Set a2d port as input
PORTC &= 0x00;  //turn off pull-up resistors
a2dInit();  //Initialize AVRLib A2d
a2dSetPrescaler(ADC_PRESCALE_DIV128); //most precise
a2dSetReference(ADC_REFERENCE_AVCC); //Use 5v ref
ir[0] = a2dConvert10bit(0);  //Read a2d pin 0

That’s it.  I actually have 2 sensors so I read both values.  Now I had to make the Atmega8 return the readings from the 2 sensors whenever the master asked for them.

First in the main function, you have to set things up.

i2cInit(); // Initialize i2c AVRlib
//Set slave address to 2
i2cSetLocalDeviceAddr(2, TRUE);
//Set slave receive function to our function
//We don’t actually use this
i2cSetSlaveReceiveHandler( i2cSlaveReceiveService );
//This function will be called when a master requests data
i2cSetSlaveTransmitHandler( i2cSlaveTransmitService );

When the master sends a “get data” request to device 2, our i2cSlaveTransmitService function will be called and that will send data back to the master.  Here is the code in the transmit function.

u08 i2cSlaveTransmitService(u08 transmitDataLengthMax, u08* transmitData)
transmitData[0] = ir[0] >> 8;
outBuffer[0] = transmitData[0];
transmitData[1] = ir[0] & 0x00FF;
outBuffer[1] = transmitData[1];
transmitData[2] = ir[1] >> 8;
outBuffer[2] = transmitData[2];
transmitData[3] = ir[1] & 0x00FF;
outBuffer[3] = transmitData[3];
sent = 1;
return 4;

I decided to go most significant byte first, so it strips that out of the int and puts it into the transmit buffer, then puts the least signifigant byte in the transmit buffer.  It repeats the operation for the 2nd sensor reading and then return that there are 4 bytes to send to the master.

On the master side, the code is very similar to the compass reading code.

void GetIR()
u08 in[4];
i2cMasterReceive(2, 4, &in[0]);
ir1 = in[0];
ir1 = ir1 << 8;
ir1 += in[1];
ir2 = in[2];
ir2 = ir2 << 8;
ir2 += in[3];

It reads from device 2 and basically does the reverse of what is in the slave to re-build the int from the MSB and LSB.  So, now I can read the ir sensors in the main program by calling this function.

Unfortunately, the front of the rc car where I can mount sensors is angled so I had to build a platform for the sensors.  I used a hinge and some screws to make it adjustable so I could dial in just the right angle to detect the low curbs, but not the ground.  It isn’t pretty, but it works.

Deathpod with ir sensors

Deathpod with ir sensors

One other thing I found when I was testing at the track is if the waypoint “moves” because of GPS error to someplace the car can’t reach (like, say, into the pond) even if you avoid the curb, the car won’t complete the course because it will never move to the next waypoint.  I came up with a couple of strategies to overcome this and implemented the simplest one.  If it determines it is on a line between the current waypoint and the next waypoint, it will drop the current waypoint and move on to the next one.  It should move along the curb with the ir sensor trying to get to the current waypoint and then at some point decide it can just abandon it and continue on.

That’s going to have to be it.  I wasn’t sure I could get the ir sensors on and working in time, but I made it.  We did some testing in the street outside the house and it looks promising.  Race day is here so we’ll just have to take what we have and hope for the best.



1. Howard Gordon - 04/17/2009

Very nicely done. I found your experience with the sonar vs infrared sensors particularly interesting. Maybe next year, they’ll put UAV’s in a separate class.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: