Proiectul consta in 2 roboti line follower. Robotii au acelasi concept, aceleasi componente importante si aceeasi programare, dar fiecare a fost construit de cate un membru al echipei. Robotii folosesc senzori pentru detectia culorii si urmaresc o linie neagra pe fond alb.
Componentele esentiale ale robotilor sunt cei 2 senzori si cele 2 servomotoare. Comportamentul robotilor este urmatorul:
Diagrama bloc:
Unitati componente:
Piese folosite:
Senzorii constau intr-o fotodioda si un fototranzistor incapsulati, conectati printr-un circuit precum cel din imagine:
Initial, motoarele erau blocate si axul nu se putea roti mai mult de 180 de grade. Pentru a elibera rotatia axului am efectuat o serie de modificari:
Senzorii sunt conectati la portul A, pinii 7 si 6, iar cele 2 motoare sunt conectate la portul A, pinul 3, respectiv portul B, pinul 7.
Alimentarea se face de la 8 baterii de 1.5V, insumand putin peste 12V, care sunt conectati la sursa de tensiune.
Codul a fost scris in C si compilat cu avr-gcc.
Input-ul de la senzori (voltaj) este trecut prin ADC si convertit intr-o valoare discreta. Aceasta valoare este comparata cu un prag determinat empiric pentru a afla daca senzorul detecteaza alb sau negru.
Comanda motoarelor se face prin cele 2 canale ale timerului 1, in modul Phase and Frequency Correct PWM. Atunci cand robotul merge inainte, unul din motoare primeste factor de umplere maxim, iar celalalalt primeste factor de umplere minim. Pentru a opri unul din motoare, opresc comanda PWM pe pinul la care este acesta conectat.
Initializarea ADC:
void ADC_init(void) { //referinta AVCC cu condesator extern pe pinul AREF; //activez ADC si il pun in modul free running (auto trigger). Prescaler de ceas la maximum. FARA intrerupere la conversie completa. ADMUX = (1<<REFS0); ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADATE); }
Primirea unei valori de la ADC:
int ADC_get(uint8_t channel) { //setez canalul de pe care vreti sa faceti citirea //fac zero bitii de MUX ADMUX &= 0b11100000; //setez canalul ADMUX |= channel; //astept sa se termine o conversie loop_until_bit_is_set(ADCSRA, ADIF); //returnez rezultatul conversiei return ADC; }
Comanda PWM pe unul din canale:
void PWM_A(uint8_t motor, int val) { PORTB = motor; OCR1A = val; _delay_ms(1); }
Algoritmul principal de miscare:
while(1) { ADCSRA &= 11101111; //setez ADIF pe 0 val1 = ADC_get(channel1); //citim valoarea de la ADC ADCSRA &= 11101111; //setez ADIF pe 0 val2 = ADC_get(channel2); //citim valoarea de la ADC if (val1 > 920 && val2 > 920){ go_forward(); } else if (val1 < 920 && val2 < 920){ go_forward(); } else if (val1 > 920){ //senzorul drept move_left_motor(); } else if (val2 > 920){ //senzorul stang move_right_motor(); } }
Ambii roboti sunt functionali si reusesc sa urmareasca linia neagra. Deoarece senzorii nu sunt amplasati imediat in fata motoarelor, unele curbe mai stranse ar putea crea probleme. Insa, in majoritatea cazurilor, robotii functioneaza corect.
Codul pentru roboti: cod_double_line_follower.zip
Datasheet ATMega16: doc2466.pdf
Datasheet Senzori RPR-220: rpr-220.pdf