• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Zlikwidowanie błędu pomiarowego czujnika odległości HC-SRO4
#1
Tworze autonomicznego robota składającego się z:
- dwóch czujników ultradźwiękowych (HC-SRo4)
- dwóch silników DC
- modułu kart mikro SD

Robot "śledzi" ściany oraz w zależności od czynności jakie wykonuje (jazda prosto, skręt w prawo, skręt w lewo) zrzuca na kartę SD cyfry 0, 1 lub 2.
Śledzenie ścian odbywa się za pomocą techniki sterownika PID.

Wzór na obliczanie prędkości silników: 
Kod:
Wall = sr04_left.Distance();
error_wall = Wall - offset;
i_wall = (i_wall + error_wall);
d_wall = (error_wall - lastError_wall);

correction_wall = Kp_wall * error_wall + Ki_wall * i_wall + Kd_wall * d_wall;

rightMotorSpeed  = 128 + correction_wall;
leftMotorSpeed = 128 - correction_wall;

Dodatkowo do robota tworzę aplikację rysującą mapy pomieszczeń na podstawie danych które robot zgrał na kartę SD.
Program rysuje mapy w następujący sposób:
- Jeżeli widzi 0 - rysuje linie do góry
- Jeżeli widzi 1 - zaczyna rysowanie kolejnych zer o -90*
- Jeżeli widzi 2 - zaczyna rysowanie kolejnych zer o 90*

Zdjęcie przykładowej trasy robota:
   

Problemem w moim projekcie jest niedokładność pomiarowa czujników. Przez co zrzucane są błędne informacje na kartę SD, a co za tym idzie mapa jest niepoprawnie rysowana przez program rysujący.
Pomyślałem więc że dobrym sposobem na zniwelowanie błędu pomiarowego będzie stworzenie tablicy np. 5 pomiarów odległości a następnie obliczenie z niej mediany, a dopiero z mediany obliczać prędkość silników.
Zaimplementowałem więc medianę: 
Kod:
int mediana(int n, int x[]) {
 int temp;
 int i, j;
 for (i = 0; i < n - 1; i++) {
   for (j = i + 1; j < n; j++) {
     if (x[j] < x[i]) {
       temp = x[i];
       x[i] = x[j];
       x[j] = temp;
     }
   }
 }
 return x[n / 2];
}
Oraz dodałem ją do wzoru PID:
Kod:
for (int i = 0; i < sizeof(distanceArray) - 1; i++) {
 distanceArray[i] =  sr04_left.Distance();
}
 
Wall = mediana(5, distanceArray);
error_wall = Wall - offset;
i_wall = (i_wall + error_wall);
d_wall = (error_wall - lastError_wall);

correction_wall = Kp_wall * error_wall + Ki_wall * i_wall + Kd_wall * d_wall;

[size=small][font=Monaco, Consolas, Courier, monospace]rightMotorSpeed  = 128 + correction_wall;[/font][/size]
leftMotorSpeed = 128 - correction_wall;

Niestety to rozwiązanie nie spełnia moich oczekiwań. Po dodaniu mediany do wzoru robot bardzo wolno "myśli". Zapewne nie rozwiązałem problemu poprawnie dlatego zwracam się z prośbą o pomoc. Mam nadzieję że wyczerpująco wytłumaczyłem problem, jeżeli nie to proszę o pytania.

Kod do progarmu:
https://pastebin.com/PqWz7HaZ

Zdjęcie robota:
   
 
Odpowiedź
#2
1. Czujnik ultradźwiękowy jest niedokładny z tego powodu, że fala dźwiękowa rozchodzi się kuliście i nie masz pewności że to co mierzysz jest odległością od ściany na przeciwko, czy od ściany obok. Dźwięki odbijają się pod różnymi kątami i nie wiadomo skąd pochodzi ten, który właśnie odebrałeś. Pomyśl o LIDAR.
2. Twój algorytm PID pracuje na liczbach zmiennoprzecinkowych. To jest jeden z najczęstszych błędów popełnianych przez arduinowców. Jak chcesz float/double, to zainteresuj się jakimś STM z FPU. Można oczywiście napisać PID na liczbach całkowitych. Wymaga to trochę innego podejścia do problemu, ale wzrost wydajności jest oszałamiający i myślę, że powinieneś się tym zainteresować.
3. Możesz trochę inaczej zarządzać czasem w programie. Nadaj funkcjom priorytety. Stwórz system przerwań .... a nie, zapomniałem że Arduino nie wspiera przerwań. Ta funkcja attachInterrupt() to jest jakieś nieporozumienie, ale nawet tym jak byś się zainteresował, to może coś wskórasz.
Jak nie, to pomyśl poważnie o STM.
Edit: Bluepill jest tańsze od Ardu!!!
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#3
(25-01-2019, 21:58)Robson Kerman napisał(a): 1. Czujnik ultradźwiękowy jest niedokładny z tego powodu, że fala dźwiękowa rozchodzi się kuliście i nie masz pewności że to co mierzysz jest odległością od ściany na przeciwko, czy od ściany obok. Dźwięki odbijają się pod różnymi kątami i nie wiadomo skąd pochodzi ten, który właśnie odebrałeś. Pomyśl o LIDAR.
2. Twój algorytm PID pracuje na liczbach zmiennoprzecinkowych. To jest jeden z najczęstszych błędów popełnianych przez arduinowców. Jak chcesz float/double, to zainteresuj się jakimś STM z FPU. Można oczywiście napisać PID na liczbach całkowitych. Wymaga to trochę innego podejścia do problemu, ale wzrost wydajności jest oszałamiający i myślę, że powinieneś się tym zainteresować.
3. Możesz trochę inaczej zarządzać czasem w programie. Nadaj funkcjom priorytety. Stwórz system przerwań .... a nie, zapomniałem że Arduino nie wspiera przerwań. Ta funkcja attachInterrupt() to jest jakieś nieporozumienie, ale nawet tym jak byś się zainteresował, to może coś wskórasz.
Jak nie, to pomyśl poważnie o STM.
Edit: Bluepill jest tańsze od Ardu!!!
Dzięki za odpowiedź  Smile 

1. Stety albo niestety jest to moja praca inżynierska stąd właśnie to tanie rozwiązanie. Nie wiedziałem o LIDAR, bardzo ciekawa sprawa, jeżeli będę robił jakiś projekt dla siebie to na pewno się zainteresuje!
2. Czy zmiana na inty trochę poprawi działanie?
3. Niestety właśnie to jest dużym ograniczeniem w moim projekcie.

Tak jak pisałem wyżej jest to projekt na prace inżynierską więc nie chce wydawać na nią jakiś większych pieniędzy. Myślisz że zmiana liczb na inty i mediana nic tu nie wskórają?
 
Odpowiedź
#4
Możesz sobie dołożyć jakiegoś ESP8266 za 16zł (lub 3$) i na nim robić obliczenia, pomiary, wysyłać do UNO po UART tylko informacje gdzie ma jechać i co zapisać na SD. Ewentualnie ESP32 (40zł lub 5$ z Chin) ogarnie również silniki (trochę niewygodnie z tym shieldem i do sprawdzenia czy pójdzie na 3.3V) i zapis SD, ESP8266 ma trochę mało pinów. Programujesz to też z Arduino IDE po dodaniu definicji dla tych płytek. Musiałbyś sprawdzić czy wszystkie biblioteki działają na innych prockach, przed zakupem wystarczy zainstalować płytki, zmienić docelową, skompilować, jak wywali błędy ewentualnie znaleźć zamienniki. https://hilo90mhz.com/arduino-esp32-esp8...son-chart/ to porównanie nie oddaje różnicy miedzy AVR i innymi prockami, wiedziałem takie gdzie różnica szła w tysiące razy, może z powodu krótkich obliczeń tutaj. Nawet na przy operacjach na pojedynczych bytach atmega328 klęka przy dzieleniu. Po wyłączeniu radia ESP8266 pobiera mniej mocy niż Atmega.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości