go away spammer

Author Topic: my $50 robot  (Read 2044 times)

0 Members and 1 Guest are viewing this topic.

Offline greywanderer012345Topic starter

  • Robot Overlord
  • ****
  • Posts: 133
  • Helpful? 2
my $50 robot
« on: August 21, 2012, 09:06:13 PM »
   An oscilloscope? Admin, you go all out. I just got my $50 robot to work about a week ago.
   I couldn't get the code to work with my setup, so I spent a pretty good amount of time trying to make the program from scratch. I didn't have any spare parts, so I didn't want to disassemble my bot to solder the additional pins necessary for PWM.
   Unfortunately, "use PWM" was the answer I got from everyone when asking about programming the servos myself. the programming is very interesting to me, so I wanted to use the simple libraries. I think I learned more about microcontrollers than most people do while making just the basic $50 bot. (I can even make sense of and use the documentation now) :D
   I ended up using a pulse, measured with a delay just like admin's, but inside of an timer interrupt routine. The nice thing about placing the code within an interrupt is that you can forget about the servos, and alter the main program as you need to. Also, because the delay is within an interrupt, its length is unaffected by any other interrupts.
   I don't have an oscilloscope, so I used AVRStudio's debugger and stopwatch to determine how many cycles were required for 1.0ms - 2.0ms. I was running my MCU with the div8 fuse enabled, so my frequency was 1MHz. In my code, speed is positive for forward and negative for backward for both servos.

   If anyone wants to try using my code, know that I am using the atmega328p. You might need to change some values for different MCUs. (eg. my MCU has a TIMSK1, but I believe the atmega8 has only TIMSK, with no #. Also, some values for setting the ADC mode were different for me than the tutorials I found for such, and you should check your MCU documentation) I do not use any header files, except those that come with the libraries you should have.
   My bot uses photoresistors that decrease resistance with increased light (opposite what's in the tutorial. There is no reason for this, I just didn't read the label right when buying them) If you have the other photoresistors, just change the if(leftEye > rightEye), etc, to the opposite.
   Also, my light sensors are mounted underneath the chassis. The goal of this was to get the robot to follow a flashlight beam on the ground, and ignore the flashlight source in my hand. (Inspired by the Follow Me Thomas toy) It works best in a dark room, making me wonder if I should have used a different resistor than the 100KOhm I used for the sensors. I used C5 and C1 (not 4&5) because my molex housings (bought locally) were too fat to use side by side.

Code: [Select]
//Photovore atmega328p @ 1MHz
//Be sure to set optimization in IDE to zero for delay to work

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

//volatile unsigned int   clock_2millisecond=0;
//^^^Uncomment the above if you want to time anything else in
//the timer ISR. Remeber to reset it to zero if it gets above
//500.
//Add a clock_second, ...minute, etc., counter if you need to

//This is used to count milliseconds by 2
volatile unsigned int   servo_2millisecond=0;
volatile unsigned int   sensor_2millisecond=0;

uint8_t leftEye = 0;
uint8_t rightEye = 0;

//speed range is -20 to 20, negative speeds = reverse
volatile int leftSpeed = 0;
volatile int rightSpeed = 0;

void DelayLoops(uint16_t nloops){
   while(nloops>0){
      nloops--;
   }
}

void InitADC() {
   ADMUX=(1<<REFS0)|(1<<ADLAR); // Aref=AVcc, Left Adjusted
   ADMUX|=0b00000101; //Start by reading pinC5
   ADCSRA|=(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // Prescalar=8, be sure to change for different MCU Hz
   ADCSRA|=(1<<ADEN); //Enable ADC
   ADCSRA|=(1<<ADSC); //Start ADC
   ADCSRA|=(1<<ADIE); //Enable ADC Interrupt
   
}

int main() {
   //Set PinD as Output
   DDRD = 0xFF;
   //Clear PORTC
   PORTC= 0x00;

   InitADC();

   //Set up the timer1
   //Set Prescaler to 8 and mode to CTC
   TCCR1B=(1<<WGM12)|(1<<CS10);

   //The below compare value for 2ms was found empirically with the debugger
   // and will differ with other frequencies
   OCR1A=2000;

   //Enable the Output Compare A interrupt
   TIMSK1|=(1<<OCIE1A);

   //Enable interrupts globally
   sei();

   //infinite loop
   while(1); //This will be skipped if optimization is used

   return 0;
}

//ISR called every 2ms. why 2? had rounding issues w/ 1ms
ISR(TIMER1_COMPA_vect) {
   clock_2millisecond++;
   servo_2millisecond++;
   if(servo_2millisecond==10)
   {
      servo_2millisecond=0;
  //Send Servo Signals

  //Right Servo (PORTD Pin 2)
  PORTD|=0b00000010;
  DelayLoops(81+rightSpeed);
  PORTD=0x00;
     
  //Left Servo (PORTD Pin 1)
  PORTD|=0b00000001;
  DelayLoops(81-leftSpeed);
  PORTD=0b00010000;
   }   
   if(clock_2millisecond>=500){
      clock_second++;
  clock_2millisecond=0;
   }
}

//Called when A/D Conversion completes
ISR(ADC_vect){
   if((ADMUX & 0b00000111) == 0b00000101){ //If current pin is C5

      // read left photosensor, the +20 is an adjustment I made
      // to account for a diffence the sensors were reading
      // when the light was in front of the bot
      leftEye=ADCH + 20;

ADMUX&=0b11111000; //Clear pin register (right 3 bits only)
ADMUX|=0b00000001; //Set pin to C1

if(leftEye < rightEye-8) // The -8 acts as a threshhold
    rightSpeed=-20;
      else
    rightSpeed=20;
     
      //Small delay, might not be necessary. I added this on the
      //same debug run as the other changes that got the bot to
      //work. This might make the ISR too long if you add more
      //code. If it makes trouble, take it out or enable nested
      //interrupts.
      DelayLoops(50);

      //start next conversion
      ADCSRA|=(1<<ADSC);
   }
   else if((ADMUX & 0b00000111) == 0b00000001){ //If current pin is C1
      rightEye=ADCH;
ADMUX&=0b11111000; //Clear pin
ADMUX|=0b00000101; //Set pin to C5
if(rightEye < leftEye-8)
    leftSpeed=-20;
      else
    leftSpeed=+20;
      DelayLoops(50);
      ADCSRA|=(1<<ADSC);
   }
}


 


Get Your Ad Here