Skocz do zawartości

Autokalibracja robota AVR C (switch)


paradox91

Pomocna odpowiedź

Program będzie działał na mikrokontrolerach ATmega 8/16/32/128 itp. pracujących na 8MHz

Program do "ręcznego" odczytywania wartości z czujników

//ustawienia ADC
//ADMUX = 0;             //MUX = 0
ADCSRA |= (1<<ADEN);      //Enable ADC
//ADCSRA |= (1<<ADSC);    //start conversion
//if(bit_is_set(ADCSRA,ADIF));  //set gdy koniec konwersji
ADCSRA |= (1<<ADPS1);     //250kHz dla 8MHz
ADMUX |= (1<<ADLAR)|(1<<REFS0);//left adjusted/ read onlu ADCH, AVcc jako napięcie odniesienia 

ADMUX = (czujnik + 96); //+96 aby ustawić ADLAR i REFS  
ADCSRA |= (1<<ADSC);    //start conversion
while(bit_is_clear(ADCSRA,ADIF));
if(ADCH > czulosc){
             //czujnik wyrył czarną linię
}
else{
	//czujnik nie wykrył czarnej linii
}

Odczyt w przerwaniu:

SIGNAL(SIG_ADC){
 if(ADCH <= czulosc){
 }
 else{
 }
}

//ustawienia ADC
ADMUX |= (1<<REFS0)|(1<<ADLAR);             //MUX = 0
ADMUX  = kanal_adc+96;
//AVCC jako napięcie odniesienia
//wynik przesunięty w lewo - można odczytywać tylko ADCH
ADCSRA |= (1<<ADIE)|(1<<ADPS1)|(1<<ADPS2)|(1<<ADATE)|(1<<ADEN);
//włączone przerwanie od adc
//dla F_CPU = 8MHz zegar adc wynosi 125kHz (dzielenie przez 64)
//włączony tryb AUTO-TRIGER

sei();   //globalne zezwolenie na przerwania
ADCSRA |= (1<<ADSC);    //start conversion
Link do komentarza
Share on other sites

Mój robot pracuje na standardzie 1MHz. Mam kwarc, ale jeszcze go nie uruchamiałem i wykorzystuję wbudowany zegar. Trochę boję się tego kwarcu, bo czytałem, że można zablokować uC...

Co do ADC, z tego co przed chwilą wyszukałem w necie, powinienem użyć przetwornika ADC, inni piszą, że czujniki powinny być podczepione pod ADC uC, ale gdzie to, bo w opisie nie ma takiego pinu. Ja korzystam z L293D - czy w takiej sytuacji da się zastosować ADC?

Nes86, zamieściłeś takie fragment kodu:

if(ADCH > czulosc){
             //czujnik wyrył czarną linię
}
else{
       //czujnik nie wykrył czarnej linii
} 

Myślałem o zrobieniu programu na zwykłych IF'ach, ale zamiast odwoływać się do polecenia "widzi linię / nie widzi linii" chciałem odnieść się do napięć na zasadzie jeśli napięcie czujnika jest niższe to... a gdy wyższe to...

Jak przerobić ten program, bo szczerze powiem, że nie przemawia do mnie, mam problemy z jego zrozumieniem 🙁

Link do komentarza
Share on other sites

Widzę, że jesteś zielony w temacie, a więc wytłumaczę to bardziej łopatologicznie. Aby odczytać napięcie z czujnika należy podłączyć czujnik (CNY70, GP2S24, KTIR0711S itp.) w taki sposób:

Wyjście podłączasz do jednego z wejść przetwornika ADC mikrokontrolera. W ATmega 16 linie portuA mogą być wykorzystane jako wejścia przetwornika ADC:

No i teraz kod. Do swojego programu musisz wpleść coś takiego:

//ustawienia ADC
//ADMUX = 0;             //MUX = 0
ADCSRA |= (1<<ADEN);      //Enable ADC
//ADCSRA |= (1<<ADSC);    //start conversion
//if(bit_is_set(ADCSRA,ADIF));  //set gdy koniec konwersji
ADCSRA |= (1<<ADPS1)|(1<<ADPS0);     //125kHz dla [b]1MHz[/b]
ADMUX |= (1<<ADLAR)|(1<<REFS0);//left adjusted/ read onlu ADCH, AVcc jako napięcie odniesienia

while(1){

//POCZĄTEK SPRAWDZANIA CZUJNIKA PODŁĄCZONEGO DO PORTUA0
ADMUX = (PA0 + 96); //+96 aby ustawić ADLAR i REFS !!!!!WYBÓR CZUJNIKA
ADCSRA |= (1<<ADSC);    //start conversion
while(bit_is_clear(ADCSRA,ADIF)); //czekaj na koniec pomiaru
if(ADCH > czulosc){ //jeśli zmierzone napięcie jest większe niż ustawiona czułość
                             //to znaczy że pod czujnikiem jest czarna linia
             //czujnik wyrył czarną linię
}
else{
       //czujnik nie wykrył czarnej linii
} 

//KONIEC SPRAWDZANIA CZUJNIKA PODŁĄCZONEGO DO PA0

//TUTAJ ANALOGICZNIE DLA INNYCH CZUJNIKÓW

}

W rejestrze ADCH po zakończeniu pomiaru masz wartość zmierzonego napięcia. np jeśli ADCH = 128 (256 * 0,5)tzn, ze na wyjściu czujnika jest napięcie 2,5V (5V * 0,5)

Link do komentarza
Share on other sites

Dzięki wielkie, już jestem bardziej w temacie.

Mam robota na uC AtMega8, czujniki podczepione do wszystkich ponów bloku C zgodnie z opisanym przez Ciebie schematem, więc wszystko powinno grać.

Mam jedna pytanie

if(ADCH > czulosc)

Wykorzystałeś tutaj zmienną czulosc, ale nie widzę, żeby miała ona przypisana jakąś wartość - mylę się? Jak ją przypisać, tzn. jak obliczyć?

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Najprostsze rozwiązanie:

czulosc = 128;

wartość 128 jest dobra jeśli masz czujniki blisko podłoża i napięcie na nich waha się od ok. 5V do ok 0V.

Inny sposób to taki, że obliczasz czułość przed każdym przejazdem. Kładziesz robota tak, żeby czarna linia znajdowała się pod środkowym czujnikiem, mierzysz przetwornikiem napięcie ze środkowego czujnika i z bocznego (albo kilku bocznych i uśredniasz) a czułość ustawiasz w połowie między odczytem z czarnej linii i z podłoża.

Jest jeszcze wiele innych możliwych rozwiązań: np. kalibracja czułości dla każdego czujnika albo kalibracja już w trakcie trwania przejazdu albo jeszcze inaczej, mierzysz napięcie na wszystkich czujnikach i wybierasz najwyższe. itp. itd i wiele innych

Link do komentarza
Share on other sites

Inny sposób to taki, że obliczasz czułość przed każdym przejazdem. Kładziesz robota tak, żeby czarna linia znajdowała się pod środkowym czujnikiem, mierzysz przetwornikiem napięcie ze środkowego czujnika i z bocznego (albo kilku bocznych i uśredniasz) a czułość ustawiasz w połowie między odczytem z czarnej linii i z podłoża.

No, i o to właśnie chodzi.

Czyli mam wykorzystać Twój kod, zapisać w dwóch zmiennych pomiar z czujnika środkowego i bocznego, dodać podzielić przez 2 i wynik przypisać zmiennej czułość?

Ale jak zmierzyć tą czułość? Czy wystarczy taki kod (przypominam, że czujniki mam przyczepione do bloku C)?

int p1, p2, czulosc;
//POCZĄTEK SPRAWDZANIA CZUJNIKA 0 PODŁĄCZONEGO DO PORTU C0
ADMUX = (PC0 + 96); //+96 aby ustawić ADLAR i REFS !!!!!WYBÓR CZUJNIKA
ADCSRA |= (1<<ADSC);    //start conversion
while(bit_is_clear(ADCSRA,ADIF)); //czekaj na koniec pomiaru 
p1 = ADSC;

//POCZĄTEK SPRAWDZANIA CZUJNIKA 1 PODŁĄCZONEGO DO PORTU C1
ADMUX = (PC1 + 96); //+96 aby ustawić ADLAR i REFS !!!!!WYBÓR CZUJNIKA
ADCSRA |= (1<<ADSC);    //start conversion
while(bit_is_clear(ADCSRA,ADIF)); //czekaj na koniec pomiaru 
p2 = ADSC;

czulosc = (p1+p2) / 2;

Link do komentarza
Share on other sites

Z tym

p1 = ADCH;

p2 = ADCH;

to strzeliłem gafę, chyba ślepy jestem, ale tego
czulosc = (p1/2)+(p2/2);
to nie rozumiem. Jak zrozumiałem mam obliczyć średnią z dwóch pomiarów, z linii i z tła. Średnia to suma wszystkich pomiarów podzielona przez ich ilość. Czemu więc moja wersja
czulosc = (p1+p2) / 2;
jest niepoprawna?

Jeszcze jedno, co to za zmienna

uint8_t
i czym różni się od
int
?

Zmienne znalazłem, ale się trochę naszukałem 🙂

Nazwa typu danych | Długość w bajtach | Zakres wartości
     int8_t      |         1         |        -128 ... 127
     uint8_t     |         1         |           0 ... 255
     int16_t     |         2         |      -32768 ... 32767
     uint16_t    |         2         |           0 ... 65535
     int32_t     |         4         | -2147483648 ... 2147483647
     uint32_t    |         4         |           0 ... 4294967295
     int64_t     |         8         | -9,22*10^18 ... 9,22*10^18
     uint64_t    |         8         |           0 ... 1,844*10^19

Czyli uint8_t to odpowiednik zmiennej byte.

Link do komentarza
Share on other sites

Zmienną "czulosc" będziesz porównywał z rejestrem ADCH który jest 8-bitowy więc dobrze by było żeby zmienna "czulosc" tez była 8-bitowa i do tego bez znaku. Dlatego właśnie uint8_t.

A teraz druga sprawa. Rozważmy taki fragment kodu:

uint8_t czulosc, p1, p2;
p1 = 125;
p2 = 200;

czulosc = (p1+p2)/2; 

po wykonaniu tego kodu zmienna "czulosc" będzie miała wartość 34, bo 125+200 = 69 a 69/2 = 34. A dlaczego 125+200 = 69 to już musisz sam wykapować 🙂

Teraz drugi kod:

uint8_t czulosc, p1, p2;
p1 = 125;
p2 = 200;

czulosc = (p1/2)+(p2/2); 

A po wykonaniu tego kodu zmienna "czulosc" będzie miała wartość 162 bo 125/2 = 62, 200/2 = 100, 100+62 = 162.

Link do komentarza
Share on other sites

Chyba doszedłem, chodzi o przekroczenie zakresu zmiennej 🙂

Mam jednak inny problem, gdy zbudowałem program bazujący na czułości 128 robot spisywał się bardzo dobrze poruszając się po brązowym linoleum z białymi liniami.

Gdy jednak wprowadziłem procedurę uśredniania wszystko diabli wzięli. już piszę o co chodzi.

Średnią obliczam na podstawie czujnika 0 i 5.

Czujniki mam ułożone w taki sposób:

          5
          2
      1      3
  0              4

Gdy po kalibracji na tej samej białej linii na brązowym linoleum zaczynam przesuwać robota na boli, to okazuje się, że czujniki głupieją. Gdy robot stoi z czujnikami 2 i 5 na linii jest wszystko OK, gdy przesunę go na pozycję 1 lub 3 też wszystko gra, ale gdy przesunę na 0 lub 5 zapalają się wszystkie diody. Gdy podniosę robota dzieje się podobnie.

Jak sprawdzić jaką wartość ma czułość po wyliczeniu tej średniej, bo nie wiem czy obliczenia są poprawne - brakuje mi chyba monitora do śledzenia wartości zmiennych 🙂

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.