Wojny robotów: sterowanie + prędkość serw

Wojny robotów

Pan Rafał przygotowuje drugi pojazd do pracy + coś tam programuje ze sterowaniem… Pewnie w następnym tygodniu zobaczymy efekty tej pracy. Porównamy też sklepowe koła z naszymi – wydrukowanymi w 3D.

Prędkość serw

Pan Tomasz wykorzystał swój układ mierzący liczbę obrotów na minutę do zbadania zależności zmiany tej prędkości od wypełnienia sygnału sterującego serwem. Serwem pracy ciągłej sterujemy podając sygnał PWM z wypełnieniem z przedziału 1000-2000 us (metoda writeMicroseconds() z klasy Servo), gdzie wartość 1500 us odpowiada zatrzymaniu serwa, a wartości 1500-2000 przekładają się na coraz szybsze obroty serwa w jedną stronę (1500-1000 us w przypadku obrotów w przeciwną stronę). Tyle teorii. A praktyka?

No właśnie – serwo serwu nie równe, a tanie serwa dlatego są właśnie tanie, bo nie trzymają się ściśle tym teoretycznym wymogom. Okazuje się, że pozycja STOP jest „gdzieś w okolicy” sygnału 1500. Obroty w prawo i w lewo też nie są równe – pomimo równego odejścia od pozycji STOP. Na poniższym wykresie widać, że odejście wypełnieniem PWM o 100 us skutkuje prędkością 117 rmp (wartość 1600 us) oraz 99 rpm (wartość 1400 us). Wykres nie jest idealnie symetryczny względem osi x=1500.

Wyniki pomiarów pierwszego przebiegu testu prękości. Pomiar trwa 1s a sygnał PWM zmienia wypełnienie co 50 us.

Oczywiście jeden pomiar to za mało, więc procedura została powtórzona dla kolejnych przebiegów, a wyniki zapisane w kolejnych plikach tekstowych. Wniosek – rezultaty są powtarzalne.

Kolejne pomiary tego samego serwa – wyniki są całkiem powtarzalne.

Mając więcej pomiarów, można policzyć odchylenie standardowe i dodać słupki błędów… ale nie przesadzajmy 😉 Dla pewności pomiarów jeden raz dwukrotnie zwiększyliśmy czas zliczania prędkości (czyli dla każdej wartości wypełnienia czekamy 2s i zliczamy impulsy) – wyniki są zgodne.

Poprzednie pomiary plus nowa seria – pomiar 2s dla każdego wypełnienia.

Wnioski:
1) prędkość nie rośnie liniowo ze zmianą wypełnienia sygnału sterującego,
2) STOP dla serwa jest „gdzieś” w okolicach 1500 us, ale drobna zmiana sygnału może już poruszyć serwo w jednym kierunku, podczas gdy ta sama wartość wypełnienia nie wystarczy by ruszyć serwo w przeciwnym kierunku,
3) prędkość nasyca się około ~200 us wartości skrajnych (1000-1200 us -> prawie jedna wartość prędkości, tak samo jak 1800-2000 us),
4) ruch w lewo i prawo nie jest symetryczny.

Dalsze prace:
Można kontynuować sprawę testowania serw, poddając tym samym próbom inny egzemplarz tego samego serwa – aby przekonać się, czy widoczne tu zachowanie jest typowe dla każdego serwa, czy jednak trafiło się nam wyjątkowy egzemplarz a inne są inne.

gnuplot

Do stworzenia wykresów „na szybko” wykorzystałem program gnuplot – świetny w takich sytuacjach (wykresy na szybko, dane z numeryki, dane z Arduino). „Surowe” dane wypisywane w oknie Monitora porta szeregowego wyglądały następująco:

Servo: 1200 Predkosc: 163.00
Servo: 1250 Predkosc: 160.00
Servo: 1300 Predkosc: 141.00
Servo: 1350 Predkosc: 124.00
Servo: 1400 Predkosc: 99.00
Servo: 1450 Predkosc: 8.00
Servo: 1500 Predkosc: 0.00
Servo: 1550 Predkosc: 87.00
Servo: 1600 Predkosc: 177.00
Servo: 1650 Predkosc: 134.00

Wystarczy przekopiować te dane do pliku tekstowego (np. serwo.txt) a następnie uruchomić gnuplot i wydać polecenie wykresu danych z pliku:

  • plot 'serwo.txt’ using 2:4

Polecenie to każe wykorzystać plik 'serwo.txt’ oraz kolumnę 2 dla x-ów, kolumnę 4 dla wartości y-ków. Jak widać nie trzeba kopiować danych do arkusza kalkulacyjnego, usuwać niepotrzebne napisy (tutaj: „Servo:”, „Predkosc:”) czy też tworzyć wykres z zaznaczonych tam komórek. Wystarczy posłużyć się prostą komendą plot podając kolumny do wykorzystania (dyrektywa using).

gnuplot w akcji – druga widoczna komenda rysuje dwie krzywe (z dwóch plików) jednocześnie na jednym wykresie.

Gnuplot ma bardzo dużo możliwości – ale tutaj wspomnę tylko o słupkach błędów – gdyby były gdzieś w pliku, np. w siódmej kolumnie, to by wystarczyło wpisać następujące polecenie do ich wyświetlenia:

plot 'serwo2.txt’ using 2:4:7 with yerror

ale cóż – my nie mamy siódmej kolumny… zamiast tego niech wykreślone będą 10% błędy, czyli ponownie wykorzystamy czwartą kolumnę, dzieląc ją przez 10:

plot 'serwo2.txt’ using 2:4:($4/10) with yerror

gnuplot ze słupkami błędów na osi y (with yerror). Komenda plot 'serwo2.txt’ using 2:4:($4/10) with yerror

A może słupki na osi x i y? czemu nie!

plot 'serwo2.txt’ using 2:4:($2/50):($4/10) with xyerror

No i powstała dygresja o gnuplocie… 😉

(c) K.G. 2021

Wojny robotów („kanapka”) + problem: BT + serwo

Wojny robotów: problem – serwa i Bluetooth (BT)

Pan Rafał oprogramowywał sterowanie swojej „kanapki” z wykorzystaniem modułu BT. Nie jest to może najlepsze rozwiązanie sterowania, ale szybkie i bezproblemowe (jasne, jasne – czytaj dalej). Proste, po włączamy dwie standardowe biblioteki Servo.h oraz SoftwareSerial.h i piszemy prosty kod.

#include <Servo.h>
#include <SoftwareSerial.h>

SoftwareSerial bt(8, 9);//RxD, TxD
Servo silnik;

void setup() {
  Serial.begin(9600);
  bt.begin(9600);
  silnik.attach(3);
  Serial.println("start!");
}

void loop() {
  if (bt.available()){
    char komenda=bt.readString());
    Serial.print("odebrano= ");
    Serial.println(komenda);//dla sprawdzenia

    switch (komenda){
      case 'W': silnik.writeMicroseconds(1000); break;  //przod
      case 'S': silnik.writeMicroseconds(2000); break;  //tyl
      case 'X': silnik.writeMicroseconds(1500); break;  //stop
    }//switch
}

A tu klops! Ilekroć przesyłane są dane przez moduł BT, to serwa „wariują”, zachowują się zupełnie nieoczekiwanie. Można to sprawdzić powyższym kodem gdzie przesyłamy 'W’ przez Bluetooth i silnik kręci się na maksa do przodu, a następnie wysyłamy z apki kolejne, nic nie znaczące znaczki (wciskamy inne, zdefiniowane przyciski, np. 'A’, 'D’ itd). Te komendy powinny zostać zignorowane (brak odpowiednich instrukcji w switch-u), a serwo powinno utrzymywać swój dotychczasowy ruch. Tak się jednak nie dzieje…

Jak zawsze najpierw należało sprawdzić przewody połączeniowe, ale to nie one okazały się przyczyną problemów. Grzebanie w internecie okazało się sukcesem – biblioteka SoftwareSerial.h korzysta z tego samego układu czasowego (timera) w Artudino co biblioteka Servo.h, do sterowania PWM. Chodzi o to, ze Arduino (a dokładniej ATmega 328P) posiada trzy niezależne timery: dwa 8-bitowe oraz jeden 16-to bitowy. Właśnie z tego ostatniego korzystają dwie wspomniane biblioteki i powstaje konflikt!

Rozwiązaniem może być alternatywna biblioteka do obsłui serw: ServoTimer2. Już sama nazwa wskazuje, że korzysta ona z drugiego timera – nie powinno być więc konfliktu z SoftwareSerial.h. Lekko zamieniamy kod programiku i sprawdzamy zachowanie serw podczas przesyłania danych z BT. Klops: jednak nie pomogło.

Jeśli nie biblioteka serw, to szukamy zamiennika do drugiej biblioteki – komunikacji szeregowej. Tutaj trafiamy na AltSoftSerial i nasze nadzieje nie gasną 😉 Ponownie modyfikujemy kod (uwaga: pinami do komunikacji są „na sztywno” pin 9 oraz 10 – nie ma możliwości wyboru, jak w przypadku biblioteki SoftwareSerial.h).

Nie poddajemy się i stosujemy dwa zamienniki bibliotek jednocześnie – bum! mamy to! działa!

#include <ServoTimer2.h>
#include <AltSoftSerial.h>

AltSoftSerial bt;//Arduino UNO -> RxD=9, TxD=10, nie ma wyboru!
ServoTimer2 silnik;

void setup() {
  Serial.begin(9600);
  bt.begin(9600);
  silnik.attach(3);
  Serial.println("start!");
}

void loop() {
  if (bt.available()){
    char komenda=bt.readString());
    Serial.print("odebrano= ");
    Serial.println(komenda);//dla sprawdzenia

    switch (komenda){
      case 'W': silnik.write(1000); break;  //przod
      case 'S': silnik.write(2000); break;  //tyl
      case 'X': silnik.write(1500); break;  //stop
    }//switch
}

Niewielkie zmiany, ale istotne. Warto zwrócić uwagę, że funkcja write() dla obiekty ServoTimer2 zapisuje mikrosekundy wypełnienia, czyli dokładnie to co robi funkcja writeMicroseconds() z obiekty Servo (biblioteka Servo.h), co jest trochę mylące. Wystarczy mieć to na uwadze i będzie OK.

Jeszcze jedno: wspomniany problem nie występuje na starszych wersjach środowiska i bibliotek Arduino IDE. Warto sprawdzić.

Wojny robotów: trzecia „kanapka” i korki (przymyślenia).

Pan Kacper buduje trzeci pojazd „kanapka”. Mamy nowe, trochę zmodyfikowane tymczasowe koła – choć drukarka 3D pracuje powoli, to i tak trzeba się natrudzić przy składaniu całej konstrukcji (jakieś 3h?).

Trzeci pojazd. Nowe koła. Ba(k)teria na ścisk!

Myślałem, że wykorzystanie korków od wina jest oryginalne – a tu się okazało, że takie zabiegi były znane i (zapewne) stosowane przynajmniej od roku 1200+. Źródła historyczne donoszą, że prawdziwy podróżnik awanturnik na szlaku musiał posiadać zestaw korków – pewnie w celach majsterkowania, bo po cóż innego miał on je w swoim ekwipunku?

Ekwipunek Geralta: korki to podstawa! Witcher 3, CDPR

Wojny robotów: szybkość obrotowa (RPM) silczka

Pan Tomasz z kolei zawziął się na zbadaniu prędkości obrotej kół (RPM = Revolutions Per Minute). Prosty układ pomiarowy (tymczasowy) pozwolił mu zmierzyć tą prędkość. Układ składa się z potencjometru do sterowania prędkością serwa Feetech FT90R (z prawej strony), oraz czujki szczelinowej (umieszczonej na – oczywiście – korku do wina) wraz z przymocowanym kołem zębatym (druk 3D).

Pomiar prędkości obrotowej serwa.

Pan Tomasz wykorzystał przerwania z Arduino UNO (a dokładniej jedno, ze zboczem narastającym). cdn…

Maskotka

BB zakończył prace nad płytą główną do Maskotki – aktualnie przygotowywane jest lepsze sterowanie prędkością kół – kontroler PID.

Kolejne spotkanie: czwartek 15:00