Skocz do zawartości

Regulator PD dla LineFollowera - problem


NightWatcher

Pomocna odpowiedź

Witam.

Stworzyłem ostatnio swojego pierwszego robota typu LineFollower. Konstrukcję mechaniczną wraz z całą elektroniką mam ukończoną, pozostało jedynie napisać odpowiedni program. Przy budowie robota posiłkowałem się wieloma poradnikami dostępnymi w internecie stąd od początku moim celem było zastosowanie regulatora PD do podążania za trasą. I tu pojawia się problem gdyż już któryś dzień z rzędu staram się dobrać odpowiednie nastawy i wszelkie próby kończą się fiaskiem. Dlatego proszę o pomoc na forum, gdzie na pewno znajdują się ludzie, którzy mają doświadczenie w tej kwestii.

Procesor użyty to Atmega 328p, program pisany jest w języku C z użyciem Arduino IDE. Robot posiada 8 czujników umieszczonych w lekkim półkolu w odległości ~14mm od siebie.

Regulator staram się stroić wyłączając część D i próbując dobrać odpowiednie Kp tak aby robot był w stanie pokonywać zakręty (gdzieś czytałem, że podobno sam człon P wystarczy aby przejechać trasę ale nie mam pojęcia ile w tym prawdy). Problem jest jednak taki, że przy małych wartościach Kp robot wypada z trasy na bardzo łagodnych zakrętach (około 30 stopni) a przy większych z trudem dojeżdża do zakrętu, gdyż na prostej dość mocno się chwieje. Włączenie części różniczkującej w moim odczuciu niewiele daje (nie widać jakiejś zauważalnej poprawy).

Być może jest to wina tego, że przy wykryciu skrętu część różniczkująca jest różna od zera tylko i wyłącznie pomiędzy samplami w których wykryto różnicę w odczycie - poźniej, pomimo wykrywania zakrętu odczyt pozostaje taki sam wobec czego różniczka znów jest zerem co sprawia, że część D była obecna w sygnale sterującym silnikami tylko przez ~5ms (= brak reakcji silników). Z drugiej strony jednak, wszystkie przykładowe kody bądź pseudokody regulatora PD dla LineFollowera wyglądały tak samo, więc nie wiem czy moja hipoteza jest prawdziwa (pewnie nie).

Poniżej zamieszczam kod. Nie jest to całkowity kod programu, wkleiłem tylko to co jest istotne z punktu widzenia regulatora PD.


const int SensorWeight[8] = { -8, -4, -2, -1, 1, 2, 4, 8};
const int SetPoint = 0;
const int NoActiveSensor = 221;

int Kp = 1;
int Td = 0;

int gain = 0;
int derivative = 0;
int feedback = 0;

int control = 0;
int baseMotorSpeed = 50;

unsigned long int startTime;


int GetSensorValues()
{
 int value = 0;
 int activeSensors = 0;

 for (int i = 0; i < 8; i++)
 {
   if (digitalRead(i))
   {
     value += SensorWeight[i];
     activeSensors++;
   }
 }

 if(!activeSensors)
   return NoActiveSensor;

 value = value / activeSensors;
 return value;
}

void SetMotors(int speed)
{
 SetLeftMotor(baseMotorSpeed + speed);
 SetRightMotor(baseMotorSpeed - speed);
}


void SetLeftMotor(int speedValue)
{
 if (speedValue<0)
   speedValue = 0;
 else if(speedValue>255)
   speedValue = 255;

 analogWrite(IA1, speedValue);
}

void SetRightMotor(int speedValue)
{
 if (speedValue<0)
   speedValue = 0;
 else if(speedValue>255)
   speedValue = 255;

 analogWrite(IB1, speedValue);
}

void PD() {
     startTime = millis();
     feedback = GetSensorValues();

     if(feedback == NoActiveSensor)
       error = previousError;
     else
       error = SetPoint - feedback;

     gain = Kp * error;
     derivative = (error - previousError) * Td;     
     control = gain + derivative;


     SetMotors(control);

     previousError = error;

     while (millis() - startTime < 5);
}

Będę wdzięczny za pomoc i z góry dziękuję.

Link do komentarza
Share on other sites

Czy koła mogą kręcić się w tył?

Czy driver silnika umożliwia jego hamowanie?

Czy w twoim programie error nie rośnie do kwadratu w funkcji odległości?

Nie wiem czy zrozumiałem dobrze twój kod ale jeśli 2 zewnętrzne czujniki są na linii to error=8+4 czyli 12 a jak linia jest na samym końcu to tylko 8?

Link do komentarza
Share on other sites

1. Tak, mogą tylko, że z różnymi trybami wygaszania prądu (o ile dobrze zrozumiałem dokumentację)

2. Z tego co wyczytałem to driver ma dostępne funkcje Coast/fast decay i Brake/slow decay, więc chyba tak (driver to HR8833)

3. Niby tak, ale nie do końca (patrz pkt. 4) - wagi czujników to po prostu kolejne potęgi dwójki - przyjmowałem już najróżniejsze, z marnym skutkiem.

4. Nie, odczyt z czujników jest dzielony przez ilość aktywnych czujników, więc dla 2 skrajnych error = 6, dla ostatniego skrajnego error = 8.

Link do komentarza
Share on other sites

Człon P powinien być liczony jak najczęściej. Ograniczenie do 5ms powinno być stosowane tylko do członu D (i ja bym je zwiększył do około 20ms, ale z tym trzeba po prostu poeksperymentować).

A wagi czujników dobrałbym bardziej liniowo w zależności od odległości.

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

Zrobiłem tak jak napisał lukix - jest nieco lepiej bo LF daje rade pokonywać łagodne i średnie zakręty, dość szybko się stabilizuje, nadal jednak ma problem z ostrymi zakrętami (po prostu wypada z trasy). Wszystko dotyczy oczywiście (póki co) małych prędkości (około 12% wypełnienia PWM), więc podejrzewam, że zwiększenie prędkości jeszcze pogorszy sprawę.

EDIT: dodam jeszcze, że robot dostaje dużego przyspieszenia przy wyjściu z zakrętu co sprawia, że gorzej mu idzie pokonanie następnego.

Link do komentarza
Share on other sites

1) Zauważyłem, że masz w kodzie zły znak w liczeniu zmiennej derivative. (powinno być previousError - error).

2) Ostre zakręty w dosłownym znaczeniu (mniej niż 90 stopni)?

3) Problem z wyjściem z zakrętu możesz rozwiązać w ten sposób, że będziesz tylko zmniejszać pwm dla jednego silnika, bez zwiększania dla drugiego.

4) Jak dalej nie będzie efektów to może pokaż jakiś filmik jak to wygląda.

Link do komentarza
Share on other sites

Jesteś pewien co do tej zmiennej derivative? Mi się wydaje, że jest liczona w dobry sposób (gdy nagle pojawi się niezerowy error, to derivative będzie mieć ten sam znak co gain wobec czego wymusi mocniejszy zakręt aby skorygować tor).

Spróbowałem zastosować sposób o którym mówiłeś - zmniejszanie PWM jednego silnika przy stałej wartości drugiego - trochę pomogło. Następnie dodałem do tego możliwość zmiany kierunku obrotów na zakręcie. Podziałało zaskakująco dobrze - na tyle dobrze, że wróciłem do poprzedniej wersji ze zmianą PWM obu silników naraz. Przy takiej konfiguracji z małymi prędkościami robot bez problemu pokonuje trasę, którą wykleiłem sobie na podłodze. Niestety przy zwiększaniu prędkości (~22% PWM, więc wciąż mało) przy mocniejszym zakręcie (około 70 stopni) robot zaczyna zachowywać się dziwnie.

Mianowicie:

1. Czasami przejedzie poprawnie (mocno hamując i bujając się przy wyjściu)

2. Czasami robiąc kilka kółek z rzędu po prostu pojedzie prosto jakby nie widział zakrętu (mimo tego, że przed chwilą kilkakrotnie go pokonał)

3. Czasami zrobi jeden obrót w miejscu i dopiero wtedy pojedzie dalej poprawną trasą

4. A czasami zawróci

Nie wiem za bardzo, w którą stronę powinienem iść z nastawami aby wyeliminować ten problem. Zmienić P/D czy może częstotliwość liczenia członu D? A może dodać inny parametr, który np. zmniejszy prędkość bazową silników przy wykryciu mocnego zakrętu?

Z góry dziękuję za wszelkie porady.

Link do komentarza
Share on other sites

Kilka razy się upewniałem z tym znakiem, a i tak się pomyliłem 😉 Masz rację - jest dobrze.

Ja już chyba za wiele nie wniosę. Musisz eksperymentować i obserwować wyniki.

Nie wiem jakie masz silniki i koła, ale np. 22% PWM dla silników Pololu 10:1 z kołami 32mm to nie jest taki zły wynik (choć da się lepiej) 😉

EDIT: Ważne są też mechaniczne kwestie - moment bezwładności, odległość czujników od osi kół itd. Może to tu jest większy problem?

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

Dzięki za pomoc. Owszem silniki to Pololu 10:1 (oryginalność przede wszystkim), koła też od Pololu dokładnie te: https://botland.com.pl/kola-pololu/147-kola-solarbotics-rw2.html Opony z bardzo klejącej gumy, świetnie zbiera kurz z podłogi 😉

Szczerze mówiąc zaskoczyłeś mnie mówiąc, ze 22% PWM to dobrze. Spodziewałem się, że na spokojnie można dojść do 60%, może 70. Ale skoro tak to jestem zadowolony z efektów. Będę eksperymentować z nastawami i innymi parametrami, jako pojawi się coś ciekawego to dam znać.

Jeszcze raz dzięki za pomoc i inspiracje. 😉

EDIT: No jeśli faktycznie problem leży w rozkładzie masy, rozstawie kół lub czymś podobny to niestety z tym już nie mogę nic zrobić 🙁

Link do komentarza
Share on other sites

Nie miałem styczności z tymi oponami, więc nie wiem jak dobre one są.

Ja na zwykłych pololu osiągałem (jeśli dobrze pamiętam) coś około 32% pwm.

Później zmieniłem koła na takie:

https://www.fingertechrobotics.com/proddetail.php?prod=ft-minisumo-wheels-1125

I teraz jestem w stanie osiągnąć 45 - 55% pwm na trasie z kątami prostymi. Opony muszą być często czyszczone, bo przyczepność bardzo szybko spada.

Przy tych 50% wydaje mi się, że można już zaczynać myśleć o jakiś miejscach na zawodach, ale na to też wpływa bardzo dużo czynników. Trzeba też pamiętać, że pwm nie przekłada się idealnie na prędkość robota.

Link do komentarza
Share on other sites

Mam jeszcze jedno pytanie - podczas wielu testów na kilku torach (nadal wyklejonych na podłodze), zmagałem się z problemem, którego nie potrafiłem rozwiązać zmianą nastaw tudzież modyfikacją programu. Otóż przy zakrętach pod kątem prostym robot czasami (w około połowie przypadków) skręcał w przeciwną stronę (czyli np. jeśli zakręt był w prawo to robot skręcił w lewo w skutek czego albo wypadł z trasy albo zawrócił). Czy ktoś ma jakiś pomysł dlaczego tak się dzieje, czy jest to po prostu coś co trzeba wyeliminować drogą eksperymentów?

Link do komentarza
Share on other sites

Ja u siebie rozwiązałem to tak, że w momencie gdy żaden czujnik nie widzi linii, robot wie w którą stronę skręcić na podstawie tego pod którym skrajnym czujnikiem (najbardziej wysunięty w lewo albo w prawo) ostatnio widział linię. Czyli podobne rozwiązanie, które już stosujesz (na podstawie kodu w pierwszym poście), ale bierz pod uwagę tylko skrajne czujniki.

Gdybyś miał skrajne czujniki przesunięte lekko do tyłu względem pozostałych to prawdopodobnie nie było by tego problemu nawet przy obecnym programie.

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.