Desktop Robot – Object Tracking With Infrared

The goal of this project was to create a desktop robot that can track or follow nearby objects.  The design had to be compact yet rugged enough to withstand the curiosity of my kids.  After many iterations, I finally ended up with a 35mm film canister at the end of a 2 degrees of freedom mini boom powered by 2 micro servos.

This desktop robot tracks nearby objects using infrared.  The MCU is an AVR Atmega328P-PU running at 16 Mhz.  Two micro servos control the vertical and horizontal motion of the boom.  At the end of the boom is a 35mm film canister with 4 IR LED's and an IR Receiver.

This desktop robot tracks nearby objects using infrared. The MCU is an AVR Atmega328P-PU running at 16 Mhz. Two micro servos control the vertical and horizontal motion of the boom. At the end of the boom is a 35mm film canister with 4 IR LED’s and an IR Receiver.

Proximity Detection

There are total of four IR emitters (Two for the horizontal axis and two for vertical axis), and one IR receiver.  The emitter LED’s are constantly alternating through an on-measure-off routine.  The sequence is the following:

Each LED takes a turn emitting while the other 3 are off.  While the LED is on, the receiver counts the number of samples where IR is detected.  Then the LED goes off and the cycle continues on to the other 3 LED's.

Each LED takes a turn emitting while the other 3 are off. While the LED is on, the receiver counts the number of samples where IR is detected. Then the LED goes off and the cycle continues on to the other 3 LED’s.

  • Turn on TOP IR LED.  Take 100 readings from the IR Receiver and count the detections.  Do this 3 times and take the average.
  • Turn on BOTTOM IR LED.  Take 100 readings from the IR Receiver and count the detections.  Do this 3 times and take the average.
  • Turn on LEFT IR LED.  Take 100 readings from the IR Receiver and count the detections.  Do this 3 times and take the average.
  • Turn on RIGHT IR LED.  Take 100 readings from the IR Receiver and count the detections.  Do this 3 times and take the average.

If the count of readings is at least 30% higher on one side of the vertical or horizontal plane, the servos will increment either up or down.

I’ll include the AVR source file for download at the end of this post but here are some snippets to illustrate how the object is tracked.
int digitalRead(int pin){
if (bit_is_clear(PINC, pin)) // The PNA4602 goes low when it detects IR so 1 if bit is clear.
{
return 1;
}
return 0;
}

int burst_left(){
l = 0;
sample_left = 0;
while(l < 100) {
sample_left = sample_left + digitalRead(receiverPin); // Take 100 readings
l++;
}
return sample_left;
}

int burst_right(){
r = 0;
sample_right = 0;
while(r < 100) {
sample_right = sample_right + digitalRead(receiverPin); // Take 100 readings
r++;
}
return sample_right;
}

int avg_left(){
output_low(PORTD,rightIR);
output_low(PORTD,topIR);
output_low(PORTD,bottomIR);
output_high(PORTD,leftIR); // Set left IR LED high
lsample1 = burst_left();
lsample2 = burst_left();
lsample3 = burst_left();
return (lsample1 + lsample2 + lsample3) / 3; // Avg of 3 samples - Should be around 100 with detection
}

int avg_right(){
output_low(PORTD,leftIR);
output_low(PORTD,topIR);
output_low(PORTD,bottomIR);
output_high(PORTD,rightIR); // Set right IR LED high
rsample1 = burst_right();
rsample2 = burst_right();
rsample3 = burst_right();
return (rsample1 + rsample2 + rsample3) / 3; // Avg of 3 samples - Should be around 100 with detection
}

void trackObject() {
float leftVal = avg_left();
float rightVal = avg_right();
if(leftVal == rightVal)
{
horizLevelCount++;
if(horizLevelCount >= 500) // If no IR is detected, go back to center
{
posHorizontal = 90; // Return to center
horizLevelCount = 0;
}
}
else if(leftVal > 90 && leftVal > (rightVal * 1.30)) {
horizLevelCount=0; // Clear level
posHorizontal = posHorizontal -1;
}
else if(rightVal > 90 && rightVal > (leftVal * 1.30)) {
horizLevelCount = 0; // Clear level
posHorizontal = posHorizontal + 1;
}
// move servos
if(posHorizontal < 15) posHorizontal = 15; // Set min horizontal limit
if(posHorizontal > 145) posHorizontal = 145; // Set max horizontal limit


turn_servo(horizontalServo,posHorizontal);
_delay_ms(5); // Things just seem to work better with this delay
}

IR Emitters and Detectors

The IR Detector is a PNA4602M.  They are currently not produced anymore but I ordered a few of them after reading David Cook’s Intermediate Robot Building book (A fabulous read, by the way).  David also has found some good replacements and thoroughly covers them in his blog.  The emitters are 940nm IR LED’s from Vishay.

The PNA4602M requires a 38khz signal from the LED’s.  This is good in one sense, since they are less susceptible to erroneous detection from normal light.  However, this does mean that I had to make sure to program one of the Atmega328’s timers to produce this frequency.

The 38Khz signal is applied to the ground side of each IR LED through the use of an NPN transformer

The 38Khz signal is applied to the ground side of each IR LED through the use of an NPN transformer

The following generates the 38 khz signal:

void Init_IR_Emitters(){
TCCR0A |= (1 << WGM01); // Set the Timer Mode to CTC
OCR0A = 25; // Sets timer to 76 Khz (Since led is toggled at 50% on 50% off,
// this is actually 38K frequency).
TIMSK0 |= (1 << OCIE0A); //Set the ISR COMPA vect
TCCR0B |= (1 << CS01); // set prescaler to 8
}

ISR (TIMER0_COMPA_vect) // timer0 overflow interrupt to keep LED's at 38 Khz
{
PORTD ^= (1<<6); // Toggle IR LEDs
}

The Circuit Board

There are two LM7805 5V voltage regulators.  One for the MCU(Atmega328) and one for the servos.  The servo bus voltage regulator has 10uf capacitors to smooth out the power supply as well as a 0.1uf capacitor as an added filter.

IR Tracking

The Servos

The servos I’m using are cheap Blue Arrow S0901 90g micro servos.  For lack of a better connection method, I hot glued the top (Vertical) servo to the bottom (horizontal) servo.  The position of the servos is determined by the following function.

Note that I had to establish some horizontal and vertical limits to keep the servos from bumping the circuit board and yanking on the wires.  If I were to redesign anything, I would have used thinner wires on the LED’s and Receiver.  The 22 ga. wire that I used tends to be very rigid.  Especially when bundled together.  The tension from the thick wires limits the range of motion of boom.

The servo expects a PWM signal at a frequency of 20 mS or 50 hz.  The position is determined by the duty cycle of the PWM signal.  The following sets the Atmega328 timer at 50 hz:
void Init_Servos(){
TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11); //NON Inverted PWM
TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10); //PRESCALER=64 MODE 14(FAST PWM)
ICR1=4999; //fPWM=50Hz (Period = 20ms Standard).
OCR1A = -1; //off
OCR1B = -1; //off
}

void turn_servo(int servo, float degrees){
pwm_period = (min_servo_us + (degrees * 10))/4; // For 600us to 2400us servo
switch(servo)
{
case 0 :
DDRB|=(1<<PB2); //Servo PWM Pin as Out
OCR1B=pwm_period; // PB2 = OCR1B
break;
case 1 :
DDRB|=(1<<PB1); //Servo PWM Pin as Out
OCR1A=pwm_period; // PB1 = OCR1A
break;
}
}

So for a standard 600 microsecond to 2400 microsecond servo, the following formula is used to calculate the correct duty cycle:
pwm_period = (600 + (degrees * 10))/4; // For 600us to 2400us servo

Here’s a video of the robot in action.

If I were to redesign this, one thing I would do is use thinner wires on the boom.  I used 22 ga. solid wire.  I found them to be very rigid and they tend to act like springs causing strain on the servos….Maybe next time!  I’m open to suggestions to improve this in any way so please comment below.

Thanks, and happy building!

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.


4 thoughts on “Desktop Robot – Object Tracking With Infrared

  • Jim Gage

    Here is a vid of one I built using a bicore circuit and a minimum # of components. I like how yours stands still and waits for the target to move or be discovered. Your board construction is also great! Very interesting, using the switching method and one rx, never seen that before. Bravo!
    link to video

    Reply
  • Erik Kringen

    Thanks Jim,

    I love the design of your phish. Very creative. The swimming action is a sweet addition. What did you use for the motor? I haven’t tried a bicore circuit yet. But now I’m intrigued.

    Reply
    • Erik Kringen Post author

      Thanks Jeremy,
      I’ve seen some designs where the robot actually tries to maintain a certain distance from the object. So basically it follows the object and when the object stops, the robot stops. I’m thinking a Sharp IR range finder would be a good sensor for that.

      Reply

Speak Your Mind

Your email address will not be published. Required fields are marked *

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>