/* * Company: Botronix * Author: AJC * Target Device: ATMEGA164P running on the Ranger Robot * Description: The robot will drive in a forward direction until an obsacle * is detected with the front bumper. After a collision has been detected, the * robot will stop, reverse direction, spin to a new direction, and drive * forward. */ #include #include //Macros #define bit_set(x,y) (x |= (1 << y)) #define bit_clr(x,y) (x &= ~(1 << y)) //Constants const uint16_t LEFT_STOP = 1520; const uint16_t RIGHT_STOP = 1500; const uint16_t LEFT_FORWARD = 1020 ; const uint16_t RIGHT_FORWARD = 2000; const uint16_t LEFT_REVERSE = 1620 ; const uint16_t RIGHT_REVERSE = 1400; const uint16_t ZTR_LEFT_LEFT = 1620; const uint16_t ZTR_LEFT_RIGHT = 1600; const uint16_t ZTR_RIGHT_LEFT = 1420; const uint16_t ZTR_RIGHT_RIGHT = 1400; //Variables enum direction {STOP, FORWARD, REVERSE, ZTR_RIGHT, ZTR_LEFT}; volatile uint8_t timer0_ovf_count; /*############################################################################ Timer/Counter0 Overflow ISR ############################################################################*/ ISR(TIMER0_OVF_vect) { timer0_ovf_count++; } /*############################################################################ Timer/Counter1 Output Compare Match A ISR ############################################################################*/ ISR(TIMER1_COMPA_vect) { } /*############################################################################ Timer/Counter1 Output Compare Match B ISR ############################################################################*/ ISR(TIMER1_COMPB_vect) { } /*============================================================================== InitPorts Initialize I/O Ports ==============================================================================*/ void InitPorts(void) { /********************************************* PORTA PA0 = Microphone PA1 = ADC1 (Light Sensor Front Left) PA2 = ADC2 (Light Sensor Rear Left) PAA = ADC3 (Light Sensor Front Right) PA4 = ADC4 (Light Sensor Rear Right) PA5 = Dip switch bit0 PA6 = Dip switch bit1 PA7 = Program **********************************************/ PORTA = 0b00011110; // enable input pin pullups (1) DDRA = 0b00000000; //0 is input, 1 is output /********************************************* PORTB PB0 = Left side odometry direction PB1 = Right side odometry direction PB2 = Right side front bumper signal PB3 = Buzzer PB4 = Left side front bumper signal PB5 = SPI MOSI PB6 = SPI MISO PB7 = SPI SCK **********************************************/ //Enable all input pin pullups (1) and set all outputs to zero PORTB = 0b01010111; DDRB = 0b10101000; //0 is input, 1 is output /********************************************* PORTC PC0 = GPIO/I2C clock PC1 = GPIO/I2C data PC2 = LED4/Line detector signal 0 PC3 = LED3/Line detector signal 1 PC4 = LED2/Line detector signal 2 PC5 = LED1/Line detector signal 3 PC6 = Line detector signal 4 PC7 = Line detector signal 5 **********************************************/ //Enable all input pin pullups (1) and set all outputs to zero PORTC = 0b11000011; DDRC = 0b00111100; //0 is input, 1 is output /********************************************* PORTD PD0 = Serial Comms RX PD1 = Serial Comms TX PD2 = Left side odometry trigger PD3 = Right side odometry trigger PD4 = Right side propulsion servo control signal PD5 = Left side propulsion servo control signal PD6 = Servo 0 control signal PD7 = Servo 1 control signal **********************************************/ //Enable input pin pullups (1) and set all outputs to zero PORTD = 0b00001101; DDRD = 0b11110010; //0 is input, 1 is output } /*============================================================================== InitTimer0() Initialize Timer/Counter0 Timer/Counter0 is used to generate blinking LED and buzzer waveforms ==============================================================================*/ void InitTimer0(void) { /* Compare Match Output A Mode = Normal port operation, OC0A disconnected COM0A1 = 0 COM0A0 = 0 Compare Match Output B Mode = Normal port operation, OC0B disconnected COM0B1 = 0 COM0B0 = 0 Force Output Compare A = off FOC0A = 0 Force Output Compare B = off FOC0B = 0 Wave Form Generation Mode = Normal WGM02 = 0 WGM01 = 0 WGM00 = 0 Clock source = clki/o Prescaler = 1024 CS02 = 1 CS01 = 0 CS00 = 0 Timer/Counter0 Output Compare Match A Interrupt = Disable OCIE0A = 0 Timer/Counter0 Output Compare Match B Interrupt = Disable OCIE0B = 0 Timer/Counter0 Overflow Interrupt = Enable TOIE0 = 1 */ TCCR0B = _BV(CS02) | _BV(CS00); TIMSK0 = _BV(TOIE0); // Overflow Interrupt Enable } /*============================================================================== InitTimer1 Initialize Timer/Counter1 Timer/Counter1 is used to generate waveforms for the propulsion servos ==============================================================================*/ void InitTimer1(void) { /* Compare Match Output A Mode = Clear OC1A on Compare Match when up-counting Set OC1A on Compare Match when down-counting COM1A1 = 1 COM1A0 = 0 Compare Match Output B Mode = Normal port operation, OC0B disconnected COM1B1 = 1 COM1B0 = 0 Force Output Compare A = off FOC1A = 0 Force Output Compare B = off FOC1B = 0 Wave Form Generation Mode = PWM, Phase and Frequency Correct, TOP = ICR1 WGM13 = 1 WGM12 = 0 WGM11 = 0 WGM10 = 0 Input Noise Canceler = Disable ICNC1 = 0 Input Capture Edge Select = Falling ICNS1 = 0 Clock source = clki/o Prescaler = 8 CS12 = 0 CS11 = 1 CS10 = 0 Timer/Counter1 Output Compare Match A Interrupt = Enable OCIE1A = 1 Timer/Counter1 Output Compare Match B Interrupt = Disable OCIE1B = 1 Timer/Counter0 Overflow Interrupt = Disable TOIE1 = 0 */ //Set ICR1 to 20,000 to start pulse at a rate of 50Hz ICR1 = 20000; //OCR range ~= 1000 to 2000 //Default OCRn to all stop OCR1A = LEFT_STOP; OCR1B = RIGHT_STOP; TCCR1A = _BV(COM1A1) | _BV(COM1B1); TCCR1B = _BV(WGM13) | _BV(CS11); TIMSK1 = _BV(OCIE1B) | _BV(OCIE1A); // Overflow Interrupt Enable } /*============================================================================== Sleep16_4ms NOP for ms * 16.4ms ==============================================================================*/ void Sleep16_4ms(uint8_t ms) { timer0_ovf_count = 0; while (timer0_ovf_count != ms); } /*============================================================================== ReadBumper Read bumper sensors, reverse logic, shift the result right, and return result ==============================================================================*/ uint8_t ReadBumper(void) { /* PB2 = Right side front bumper signal PB4 = Left side front bumper signal */ uint8_t pinb_temp; pinb_temp = PINB; pinb_temp = ~pinb_temp; //Bumper switch is active low, make postive logic if(pinb_temp & 0b00000100) { //set bit3 pinb_temp |= 0b00001000; } else { //clear bit3 pinb_temp &= 0b00010000; } pinb_temp = pinb_temp >> 3; pinb_temp &= 0b00000011; return pinb_temp; } /*=============================================== LEDOn Turn LED on ===============================================*/ /* PC2 = LED5/Line detector signal 0 PC3 = LED4/Line detector signal 1 PC4 = LED3/Line detector signal 2 PC5 = LED2/Line detector signal 3 */ void LEDOn(uint8_t on) { switch(on) { case(1): //illum LED1 bit_clr(PORTC,PC5); break; case(2): //illum LED2 bit_clr(PORTC,PC4); break; case(3): //illum LED3 bit_clr(PORTC,PC3); break; case(4): //illum LED4 bit_clr(PORTC,PC2); break; } } /*=============================================== LEDOff Turn LED off ===============================================*/ /* PC2 = LED5/Line detector signal 0 PC3 = LED4/Line detector signal 1 PC4 = LED3/Line detector signal 2 PC5 = LED2/Line detector signal 3 */ void LEDOff(uint8_t off) { switch(off) { case(1): //darken LED1 bit_set(PORTC,PC5); break; case(2): //darken LED2 bit_set(PORTC,PC4); break; case(3): //darken LED3 bit_set(PORTC,PC3); break; case(4): //darken LED4 bit_set(PORTC,PC2); break; } } /*============================================================================ * Maneuver *============================================================================*/ void Maneuver(uint8_t val) { switch(val) { case(STOP):/* stop*/ OCR1A = LEFT_STOP; OCR1B = RIGHT_STOP; break; case(FORWARD):/* forward*/ OCR1A = LEFT_FORWARD; OCR1B = RIGHT_FORWARD; break; case(REVERSE):/* reverse*/ OCR1A = LEFT_REVERSE; OCR1B = RIGHT_REVERSE; break; case(ZTR_RIGHT):/* ztr right*/ OCR1A = ZTR_RIGHT_LEFT; OCR1B = ZTR_RIGHT_RIGHT; break; case(ZTR_LEFT):/* ztr left*/ OCR1A = ZTR_LEFT_LEFT; OCR1B = ZTR_LEFT_RIGHT; break; default:/* stop*/ OCR1A = LEFT_STOP; OCR1B = RIGHT_STOP; break; } } /*=============================================== Wander Perform maneuvers based on bumper sensors ===============================================*/ void Wander(uint8_t bumper) { switch(bumper) { case(0): //no collision, move forward Maneuver(FORWARD); break; case(1):/* collision on the right, move left*/ LEDOn(4); Maneuver(STOP); Sleep16_4ms(15); Maneuver(REVERSE); Sleep16_4ms(90); Maneuver(ZTR_LEFT); Sleep16_4ms(33); //Maneuver(FORWARD); LEDOff(4); break; case(2):/* collision on the left, move right*/ LEDOn(1); Maneuver(STOP); Sleep16_4ms(15); Maneuver(REVERSE); Sleep16_4ms(90); Maneuver(ZTR_RIGHT); Sleep16_4ms(33); //Maneuver(FORWARD); LEDOff(1); break; case(3):/* collision on the right and left, move right*/ LEDOn(1); LEDOn(4); Maneuver(STOP); Sleep16_4ms(15); Maneuver(REVERSE); Sleep16_4ms(90); Maneuver(ZTR_RIGHT); Sleep16_4ms(33); //Maneuver(FORWARD); LEDOff(1); LEDOff(4); break; default: Maneuver(STOP); } } /*=============================================== Main ===============================================*/ int main(void) { uint8_t bumper; uint8_t sleep = 3; InitPorts(); InitTimer1(); InitTimer0(); /* enable interrupts */ sei(); //Clear LEDs (LEDs are active low!!) PORTC = PORTC | 0b00111100; //Pause 2 seconds before going Sleep16_4ms(122); //Knight Rider /* while(1) { Sleep16_4ms(sleep); LEDOn(1); Sleep16_4ms(sleep); LEDOn(2); Sleep16_4ms(sleep); LEDOff(1); Sleep16_4ms(sleep); LEDOn(3); Sleep16_4ms(sleep); LEDOff(2); Sleep16_4ms(sleep); LEDOn(4); Sleep16_4ms(sleep); LEDOff(3); Sleep16_4ms(sleep); LEDOn(4); Sleep16_4ms(sleep); LEDOn(3); Sleep16_4ms(sleep); LEDOff(4); Sleep16_4ms(sleep); LEDOn(2); Sleep16_4ms(sleep); LEDOff(3); Sleep16_4ms(sleep); LEDOn(1); Sleep16_4ms(sleep); LEDOff(2); }*/ while(1) { bumper = ReadBumper(); Wander(bumper); } switch(bumper) { case(0): //no collision, move forward break; case(1):/* collision on the right, move left*/ LEDOn(1); Sleep16_4ms(sleep); LEDOff(1); break; case(2):/* collision on the left, move right*/ LEDOn(4); Sleep16_4ms(sleep); LEDOff(4); break; case(3):/* collision on the right and left, move right*/ LEDOn(1); LEDOn(4); Sleep16_4ms(sleep); LEDOff(1); LEDOff(4); break; default: Maneuver(STOP); } #if 0 Sleep16_4ms(sleep); LEDOn(1); for(index = 2; index < 5; index++) { Sleep16_4ms(sleep); LEDOn(index); Sleep16_4ms(sleep); LEDOff(index - 1); } Sleep16_4ms(sleep); LEDOn(4); for(index = 3; index > 0; index--) { Sleep16_4ms(sleep); LEDOn(index); Sleep16_4ms(sleep); LEDOff(index + 1); } #endif return 0; }