Adding Infrared Distance Sensors to an AVR Atmega32
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 a sonar like this 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.
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 = 0×00; //Set a2d port as input
PORTC &= 0×00; //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] & 0×00FF;
outBuffer[1] = transmitData[1];
transmitData[2] = ir[1] >> 8;
outBuffer[2] = transmitData[2];
transmitData[3] = ir[1] & 0×00FF;
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.
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.
9 Responses to “Adding Infrared Distance Sensors to an AVR Atmega32”
Comment from Jesse
Time June 7, 2009 at 7:08 am
Do you know if detecting the ground is a common problem with ultrasonic sensors on robots/autonomous vehicles? I’ve seen these sensors on other machines, but haven’t heard of this issue.
Have you notice any adverse characteristics of the IR sensors in different lighting conditions? I’ve heard there can be problems sometimes.
Comment from aliasmrjones
Time June 7, 2009 at 10:30 am
I have seen this issue before as well. It isn’t a problem per se, but just something to consider with sonar. It’s a double edged sword, really. Ultrasonic sensors are very good for general object detection because they will detect anything in a cone of 35-45 degrees. Infrared is more like a laser beam – it will detect something only in a pencil-beam straight ahead. The sonar cone is, however, 3 dimensional so it will detect something 35 degrees up and down as well as left and right. So, If the untrasonic sensor is very close to the ground, as it was in my case, it will detect the ground about 18 inches in front of the car. If it is higher off the ground, it will pick up the ground farther out. For example, when I moved the sensor about 3 feet off the ground, I could detect objects about 3 feet away. If my car had moved slower, 18 or 20 inches of object detection might have been fine, but I was competing in a speed race so I needed the car to go as fast as possible and that means detecting objects as far away as possible. It was also interesting that in my house on carpet, I didn’t see this problem because the carpet absorbed the sound waves from the sonar rather than bouncing them back to the sensor. The street was very rough, however, and so bounced the sound waves back to the sensor well. (or badly depending on your perspective lol)
I was concerned about using the IR sensors in direct sunlight, but I had no issues at all. It is possible that sunlight reduced the distance the sensors were able to detect the curb. The IR sensors were never blinded by sunlight to the point that they didn’t detect the curb and the IR sensors outperformed the sonars in every situation I tested.
Comment from Lee
Time June 14, 2009 at 10:28 am
What about the possibility of turning your IR sensors into scanners? Basically mount them on servos and use the position along with the distance reading to build a picture of what is in front of you. Do the IR sensors have high enough response times to make something like that feasible?
Comment from jesse
Time June 14, 2009 at 10:30 am
That’s interesting. Thx for the reply. I have another question: did you have your truck turn as soon as it detected an object, or did you have it turn at a certain distance?
Comment from aliasmrjones
Time June 14, 2009 at 2:00 pm
The IR sensors constantly emit a voltage – the higher the voltage, the closer the object. So, it is certainly possible to mount one on a servo and take a 90 or 120 degree scan in front of the vehicle to create a distance “map”. It is a balancing act against how fast you want to be able to move, though. With 2 IR sensors mounted at angles to the left and right, you can take constant readings from these 2 sensors and if you detect something, turn in the direction of the sensor with the lowest voltage (which indicates farther distance to the object.) You get faster reading of an object because you don’t have to wait for the servo to turn. In the case of this particular race, the main obstacles were curbs, which are basically linear obstacles. They run around the course in a straight line to infinity and if you find one, you probably want to follow it until you get to a place where you want to switch to the next waypoint. So, for this situation, having 2 IR sensors on the front pointed at angles to ether side allows both quick, constant reading of both sensors and following a curb if one is detected. The sensors are only $15 or $20 each so buying an extra IR sensor is about the same cost as buying a servo. Now, if you wanted to have more intelligence in the bot to get to a certain goal or if there were other types of obstacles to avoid, etc., a servo mounted sensor might be a better choice. For a race like this one, though, having 2 sensors allows you to run faster.
Comment from aliasmrjones
Time June 14, 2009 at 2:11 pm
I actually used proportional steering. The sensors emit a voltage – the higher the voltage, the closer the object. If either sensor has a voltage higher than a threshold value, it activates object avoidance. First the value of the left and right sensors are compared. If the left sensor value is less than the right one (meaning turn left), the direction value is -1, otherwise it is 1 (indicating turn right). Then the sensor reading of the sensor with the higher value is multiplied by a scaling factor to get the turn amount. The turn amount is then multiplied by the direction value to get a relative bearing and this is fed to my steer function to turn the wheels. The relative bearing is in the range -180 to +180. So, to sum up. If either sensor value is larger than a threshold value (to eliminate sensor noise), the car turns – the closer the object detected, the farther it turns the wheels. This lets us turn to avoid objects, and the proportional steering also helps to follow a curb if the object happens to be a curb by smoothing out the turning.
Comment from Settie
Time June 24, 2009 at 11:09 am
I was reading somewhere that since there is the curved voltage that is outputed depending upon distance there becomes a problem when you get decently close to an object because the output voltage is then the same as if you were futher away from the object. Did you have any troubles with this?
Comment from aliasmrjones
Time June 24, 2009 at 1:34 pm
I did see this effect, however, even when objects were quite close, the voltage was above my “avoid” threshold so it didn’t cause me any problems.









Comment from Howard Gordon
Time April 17, 2009 at 11:51 am
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.