Skocz do zawartości

ADC Atmega8 wall follower


aixI

Pomocna odpowiedź

Cześć. Ostatnio próbuję ogarnąć ADC w Atmedze8, ale to co robię nie satysfakcjonuje mnie do końca.

Mam pomysł na jakiś projekt Chce zrobić takie coś: jak jest po lewej stronie przeszkoda (umówmy się a'la ścianka) to robot ma jechać prosto (nie skręcać na prawo i lewo) tylko w miarę możliwości jechać prosto - tzn. równolegle do ścianki, a jak zjedzie ze ścianki i czujnik nic nie widzi po lewej stronie to robot skręca w lewo, jak jest ścianka przed nim to skręca w prawo (skręca w prawo, gdy lewy i środkowy czujnik coś widzą) I chciałem do tego użyć ADC tylko dokładnie nie wiem jak napisać program, czy wystarczy do tego parę czujników (dioda ir + fototranzystor), czy jeszcze jakieś inne rzeczy? Proszę o podpowiedzi.

AixI.

Link do komentarza
Share on other sites

Masz kilka rozwiązań:

1. Przełączniki krańcowe, i niech robot cały czas dotyka ściany i jedzie wzdłuż niej, a to czy robot widzi ścianę czy nie sprawdzasz tak jak zwykłe przyciski

2. Druga opcja: dioda IR oraz TSOP na 36kHz.

W tym przypadku diodą generujesz sygnał 36kHz, a inną nóżką proca sprawdzasz stan na odbiorniku TSOP, jeżeli na TSOPIE będzie stan niski, znaczy że sygnał z diody IR dociera do TSOPA, czyli robot widzi ścianę. Czułość regulujesz za pomocą rezystora podłączonego pod diodę IR.

Nie potrzebujesz w tym przypadku ADC.

Masz jeszcze inne opcje np. zastosowanie czujnika cyfrowego SHARP 10cm, możesz też złożyć sam jakiś moduł czujnika np. z HSDL-9100 no ale Tobie chyba nie o to chodziło, więc to pomijam.

Link do komentarza
Share on other sites

Dzięki za podsunięcie pomysłów, ale jak sprawdzałem na czujniku złożonym z diody ir i fototranzystora + komparator, to jeżeli czujnik "widzi" ścianę to jedzie prosto - jedzie prosto, ale może mieć jakieś wychylenie w lewo lub w prawo. I raczej równolegle nie będzie jechał.

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

Jeśli temat jest dla Ciebie duży to spróbuj go podzielić na mniejsze kawałki - takie są łatwiejsze do ogarnięcia i przemyślenia.

Zacznij od podziału na algorytm (program) i na sprzęt (czujniki, silniki, zasilanie). Algorytm wall-followera wydaje się dość prosty ale miej na uwadze, że będzie on pracował na takich danych wejściowych jakie mu dostarczysz. Jeśli zrobisz czujniki dwustanowe, wszystko jedno optyczne czy zwykłe przełączniki, to będą musiały mu wystarczyć informacje typu bliżej/dalej niż np. 8cm od ściany. Czujniki analogowe - też wszystko jedno jakie (optyczne, ultradźwiękowe itd) powiedzą jak daleko od ściany jesteś. To duża różnica i dużo fajniejsza zabawa.

Zawsze możesz poświęcić chwilę na drobną symulację takiego robota. Zamykasz oczy i wyobrażasz sobie, że siadasz w czarnej kabinie bez okien. Przed oczami masz trzy lampki od trzech czujników a pod rękami dwa joysticki od silników. Czy jesteś w stanie takim sprzętem jechać wzdłuż połamanej ściany labiryntu? Na pewno tak więc i Twój algorytm sobie poradzi. Czy jeśli zamiast lampek będziesz miał wskaźniki odległości będzie większa frajda? Jasne bo możesz bawić się w przybliżanie/oddalanie od ściany, wiesz jak daleko masz przeszkodę z przodu itd.

Podejmując decyzje o czujnikach masz już jakiś etap za sobą. Teraz weź na warsztat sterowanie silnikami: czy chcesz mieć jedno- czy dwukierunkowe, czy "analogowe" szybciej-wolniej czy tylko włącz-wyłącz? Zawsze możesz w myślach wsiąść do takiego sprzętu i znów pojechać wzdłuż ściany. Bez wstecznego da się ale czy będzie łatwo? Czy analogowe sterowanie prędkością jest potrzebne? I tak po kolei rozwalasz cały projekt.

Potem, mając już sprzęt skompletowany w głowie robisz ostateczną symulację w ulubionym fotelu i będąc zadowolonym z jazdy, spisujesz to wszystko co robiłeś w myślach. To samo będzie musiał zrobić Twój algorytm. Cofałeś się gdy przestrzeliłeś zakręt? Będziesz musiał to uwzględnić. Jechałeś powoli i zdążałeś z reakcjami silników na nieprzewidziane przeszkody? OK, będzie łatwiej.

Przetwornik A/C jest tylko małą częścią, interfejsem między światem wielkości analogowych a liczbami w procesorze. Napisz konkretnie czego nie wiesz albo nie czujesz, choć na etapie planowania możesz spokojnie założyć, że to naprawdę działa i Twój algorytm dostaje liczby będące odpowiednikami odległości od ścian, napięć zasilania czy czego tam jeszcze potrzebujesz.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

No to tak:

*Czujniki jakich chciałbym użyć to dioda ir + fototranzystor (jak mi się wydaję to w takiej formie mogą one działać jako czujniki analogowe)

*Sterowanie silnikami: dwukierunkowe, na razie wystarczyłaby mi jazda tylko do przodu - jazda wstecz mnie nie interesuje.

Jak chodzi o ADC to nie wiem jak napisać program (np. na jeden czujnik) żeby w odległości ok. 5cm jechał od ściany, a jak ta odległość będzie większa od 5cm to (powiedzmy) skręca w lewo, żeby wyrównać, a jeżeli odległość będzie mniejsza to będzie skręcał w prawo, żeby wyrównać.

Jeżeli ustawie koniecznie białą ściankę przed czujnik w odległości ok. 5cm to na wyjściu jest 0,30V przy aku. na full naładowanym.

Link do komentarza
Share on other sites

No to znów siadasz w fotelu 🙂 Widzisz przed sobą wskźnik odległości od np. lewej ściany? Co robisz, żeby jechać wzdłuż niej? Obierasz sobie jakąś odległość bazową, a potem starasz się ją utrzymywać, prawda? Czyli sprawdzasz czy to co pokazuje wskaźnik jest większe czy mniejsze od odległości bazowej. Wynik jest wielkością błędu. Robisz więc zwykłe odejmowanie tego co pokazuje wskaźnik (przetwornik A/C) od ustalonej "bazy" odległości i po znaku różnicy dowiadujesz się czy jesteś za blisko czy za daleko. A co robią wtedy Twoje ręce? Przy jeździe prosto pchają oba joysticki mniej więcej równo ale kiedy błąd staje się niezerowy, jedną trochę przyciągasz a drugą trochę odpychasz joya i tym samym robisz delikatny skręt. Ustalasz więc jakiś poziom wysterowania (PWM) silników dla jazdy prosto po czym wyliczony wcześniej błąd dodajesz lub odejmujesz od tego poziomu bazowego dla jednego i drugiego silnika. Wcześniej możesz błąd pomnożyć przez jakąś stałą P, bo to co daje wskaźnik jest w jakichś jednostkach a to co potrzebują silniki jest w jakichś innych. Od wielkości tej stałej będzie zależała czułość tego regulatora (tak, zrobiłeś regulator typu P) odległości. Jeśli stała będzie duża to reakcje będą gwałtowne, bo zmiany PWM będą duże. I odwrotnie. Proste? To oczywiście nie wszystko ale Tobie też coś musi zostać do wymyślenia 🙂

Link do komentarza
Share on other sites

Hmm. Odległość bazowa to 5cm, tak? Czyli jeżeli robot jest za blisko ściany to jest mniejszy od odległości bazowej i analogicznie jak jest zbyt daleko ściany - czyli jest większy od odległości bazowej, dobrze myślę?

Robisz więc zwykłe odejmowanie tego co pokazuje wskaźnik (przetwornik A/C) od ustalonej "bazy" odległości

Czyli jak mam w kodzie "granice" 300 i to jest ok. 5cm to od tego odejmuję?

Ustalasz więc jakiś poziom wysterowania (PWM) silników dla jazdy prosto

Dla jazdy prosto może być ustawione na 200. A wtedy, gdy trzeba skręcić trzeba od odpowiedniego PWM'a odjąć lub dodać jakiś wynik?

Mam nadzieję, że dobrze zrozumiałem 😉 Ale jak to dokładnie napisać w Bascom'ie?

Link do komentarza
Share on other sites

Czyli jak mam w kodzie "granice" 300 i to jest ok. 5cm to od tego odejmuję?

Skoro masz granicę 300, to jeśli zbliżysz się do ściany i napięcie sygnału z czujnika wzrośnie np. do 400, to będziesz miał -100. Jeśli robot odjedzie od ściany i napięcie zmaleje np. do 200, będziesz miał +100. Po znaku jesteś w stanie powiedzieć czy robot jest za blisko, czy za daleko od ściany, a wartość po znaku mówi Ci jak bardzo jest za blisko/za daleko. Im większa ta wartość, tym mocniej musisz "skręcić" żeby robota naprowadzić na właściwą drogę, czyli PWM dla jednego silnika zwiększasz (albo dla drugiego silnika zmniejszasz) tak, żeby różnica prędkości między silnikami była tym większa, im dalej/bliżej od ściany jest robot.

'założenie - ściana jest po prawej stronie robota

roznica = granica - odczyt
if (roznica > 0) 'za daleko od sciany
 pwm1a = 127 + roznica 'lewy silnik szybciej
 pwm1b = 127 - roznica 'prawy silnik wolniej
else if (roznica < 0) 'za blisko sciany
 pwm1a = 127 - roznica 'lewy silnik wolniej
 pwm1b = 127 + roznica 'prawy silnik szybciej
else 'na granicy
 pwm1a = 255 'lewy silnik na maksa
 pwm1b = 255 'prawy silnik na maksa
end if

Oczywiście kod będzie nie kompletny, bo potrzebne są jeszcze warunki zabezpieczające przed sytuacją, gdy zmienna 'roznica' będzie miała wartość większą od 128 lub mniejszą od -128, ale ogólną ideę powinieneś zrozumieć. czasami zmienną 'roznica' trzeba będzie podzielić przez jakąś liczbę, żeby robot nie reagował zbyt gwałtownie, ale to już sama zabawa, której nikt za Ciebie nie odhaczy. Można nawet się pokusić o pełną implementację regulatora proporcjonalnego, czy nawet proporcjonalno-różniczkującego, żeby robot jeździł płynniej.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Dzięki. Rozjaśniłeś mi sytuację, wczoraj jeszcze szukałem w Internecie informacji o regulatorze P, ale to co znalazłem to tylko teoria.

Próbuję sobie ogarnąć to co napisałeś i mam pytanie:

roznica = granica - odczyt

Tutaj muszę pewnie przyjąć jakieś liczby, tak? Granica to 300, różnica skąd ją wziąć? i ten odczyt? - tego nie kapuję. Może źle myślę, ale "odczyt" jest z ADC?

Link do komentarza
Share on other sites

odczyt z ADC, natomiast granica niech będzie u Ciebie wartością stałą, np. 300, następnie podczas testów będziesz zmieniał wartość granicy zależnie od tego jak będzie się zachowywał robot.

No a różnica jest wynikiem operacji: granica - odczyt

  • Lubię! 1
Link do komentarza
Share on other sites

Na spokojnie później przeczytałem to co napisał Nawyk i rozplanowałem sobie to, i doszedłem to tego co Ty mi napisałeś, ale i tak postawię Ci za to piwo.

[ Dodano: 19-07-2013, 20:06 ]

Edit:

Spróbowałem napisać program z wykorzystaniem tego co napisał Nawyk i wyszło mi coś takiego:

$regfile = "m8def.dat"
$crystal = 1000000

'Konfiguracja przetwornika analog-cyfra (ADC)
Config Adc = Single , Prescaler = Auto

'Konfiguracja sterowania sprzętowym PWM
Config Timer1 = Pwm , Pwm = 8 , Prescale = 1 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down

Config Portb = Output

Silnik_lewy_a Alias Portb.4
Silnik_lewy_b Alias Portb.0
Silnik_prawy_a Alias Portb.5
Silnik_prawy_b Alias Portb.3

Const Granica = 300

Dim W As Word
Dim Czujnik1 As Word

'założenie - ściana jest po prawej stronie robota
Roznica = Granica - Odczyt  --> tu jest błąd: Invalid datatype [[0007]] Line: 26

Do

If(roznica > 0) --> tu jest błąd: Unknown statament [IF(ROZNICA > 0)] Line: 30                                            'za daleko od ściany

Pwm1a = 127 + Roznica                                       'lewy silnik szybciej
Pwm1b = 127 - roznica                                       'prawy silnik wolniej

Else If(roznica < 0)                                        'za blisko ściany

Pwm1a = 127 - roznica                                       'lewy silnik wolniej
Pwm1b = 127 + Roznica                                       'prawy silnik szybciej

Else                                                        'na granicy

Pwm1a = 255                                                 'lewy silnik na maksa
Pwm1b = 255                                                 'prawy silnik na maksa

End If

Loop
End


Odczyt:
Start Adc
W = Getadc(5)
W = Getadc(5)
Stop Adc
Czujnik1 = W
Return



I jeszcze jeden błąd: LOOP expected Line: 0

Prosiłbym Was o sprawdzenie, czy to co na razie napisałem ma sens.

Tylko, że ukazują się 3 błędy. Dokładnie nie wiem odkąd zacząć program (gdzie wpisać Do, czy przed "Roznica = Granica - Odczyt", czy po tym)

Nie wiem, czy nie trzeba po If'ie dać Then przy regulatorze P. Sorry za takie pytania, ale pierwszy raz z takim czymś mam styczność 😃

W tym kodzie, który tutaj wkleiłem nie deklarowałem zmiennych - teraz to zrobiłem ale i tak są nadal te błędy.

------------------------------------------------------------------------------

Edit:

poprawiłem ten kod i kompilator nie pokazuje błędów, ale nie jestem pewny, czy kod jest ok.

$regfile = "m8def.dat"
$crystal = 1000000

'Konfiguracja przetwornika analog-cyfra (ADC)
Config Adc = Single , Prescaler = 64 , Reference = Avcc

'Konfiguracja sterowania sprzętowym PWM
Config Timer1 = Pwm , Pwm = 8 , Prescale = 1 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down

Config Portb = Output

Silnik_lewy_a Alias Portb.4
Silnik_lewy_b Alias Portb.0
Silnik_prawy_a Alias Portb.5
Silnik_prawy_b Alias Portb.3

Const Granica = 300

Dim W As Word
Dim Czujnik1 As Word
Dim Odczyt As Word
Dim Roznica As Integer

'założenie - ściana jest po prawej stronie robota
Roznica = Granica - Odczyt

Do

If Roznica > 0 Then                                         'za daleko od ściany

  Pwm1a = 127 + Roznica                                    'lewy silnik szybciej
  Pwm1b = 127 - Roznica                                    'prawy silnik wolniej

Elseif Roznica < 0 Then                                     'za blisko ściany

  Pwm1a = 127 - Roznica                                    'lewy silnik wolniej
  Pwm1b = 127 + Roznica                                    'prawy silnik szybciej

Else                                                        'na granicy

  Pwm1a = 255                                              'lewy silnik na maksa
  Pwm1b = 255                                              'prawy silnik na maksa

End If

Loop
End


Odczyt:
Start Adc
W = Getadc(5)
W = Getadc(5)
Stop Adc
Czujnik1 = W
Return

Co poprawiłem:

*Usunąłem spację pomiędzy "Else, a If - czyli z tego Else If na Elseif".

*Dopisałem zmienne.

*Usunąłem nawiasy "If (roznica > 0) i If (roznica < 0)

---------------------------------------------

Edit:

Ale się rozpisałem 😃

Poprawiłem jeszcze raz ten kod i jakoś działa, tylko mam wrażenie, że robot przy "mocniejszym zakręcie" wjeżdża w ścianki.

Tu poprawiony kod:

$regfile = "m8def.dat"
$crystal = 1000000

'Konfiguracja przetwornika analog-cyfra (ADC)
Config Adc = Single , Prescaler = 64 , Reference = Avcc

'Konfiguracja sterowania sprzętowym PWM
Config Timer1 = Pwm , Pwm = 8 , Prescale = 1 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down

Config Portb = Output
Config Portd = Output
Dioda Alias Portd.7

Silnik_lewy_a Alias Portb.4
Silnik_lewy_b Alias Portb.0
Silnik_prawy_a Alias Portb.5
Silnik_prawy_b Alias Portb.3

Const Granica = 100

Dim W As Word
Dim Czujnik1 As Word
Dim Roznica As Integer

Set Silnik_lewy_a
Reset Silnik_lewy_b
Set Silnik_prawy_a
Reset Silnik_prawy_b

Do

'założenie - ściana jest po prawej stronie robota
Roznica = Granica - Czujnik1

Gosub Odczyt
If Roznica > 0 Then                                         'za daleko od ściany
  Set Dioda
  Pwm1a = 127 + Roznica                                    'lewy silnik szybciej
  Pwm1b = 127 - Roznica                                    'prawy silnik wolniej

Elseif Roznica < 0 Then                                     'za blisko ściany
  Reset Dioda
  Pwm1a = 127 - Roznica                                    'lewy silnik wolniej
  Pwm1b = 127 + Roznica                                    'prawy silnik szybciej

Else                                                        'na granicy

  Pwm1a = 255                                              'lewy silnik na maksa
  Pwm1b = 255                                              'prawy silnik na maksa

End If

Loop
End


Odczyt:
Start Adc
W = Getadc(5)
W = Getadc(5)
Stop Adc
Czujnik1 = W
Return
Link do komentarza
Share on other sites

To ostre skręcanie może być spowodowane właśnie zbyt dużą "korektą" w stosunku do błędu - może spróbuj pomnożyć różnicę przez jakąś liczbę, np. 0.8 zanim dodasz/odejmiesz ją od 127? I przydałby się warunek na wypadek, gdyby zmienna 'roznica' przekroczyła 128.

Wystarczy:

if roznica>128
roznica = 128
elseif roznica<-128
roznica = -128
end if

Coś w ten deseń, po każdym "ścianowym" warunku

Link do komentarza
Share on other sites

Wkleiłem Twój fragment kodu do swojego i jest ok, ale jak Napisałeś wcześniej, żebym pomnożył "roznice" przez, np. 0.8 to mam error - Invalid datatype

Napisałem to tak:

Pwm1a = 127 + Roznica * 0.8
Pwm1b = 127 - Roznica * 0.8

to samo zrobiłem z drugim kawałkiem kodu. Nie wiem dokładnie, czy tutaj to mnożyć, czy też tu:

Roznica * 0.8 = Granica - Czujnik1

------

Edit:

Czy taka konstrukcja jest w miarę ok? Czy lepiej jeden czujnik po prawej i lewej stronie, i jeszcze jeden czujnik pośrodku.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.