Spisu treści:

Wallace - Robot autonomiczny DIY - Część 5 - Dodaj IMU: 9 kroków
Wallace - Robot autonomiczny DIY - Część 5 - Dodaj IMU: 9 kroków

Wideo: Wallace - Robot autonomiczny DIY - Część 5 - Dodaj IMU: 9 kroków

Wideo: Wallace - Robot autonomiczny DIY - Część 5 - Dodaj IMU: 9 kroków
Wideo: ⚡Zaprogramuj robota Delta w symulatorze Codesys z użyciem G-kodów 2024, Listopad
Anonim
Image
Image

Idziemy razem z Wallace'em. Nazwa Wallace pochodzi z połączenia „Wall-E” i z poprzedniego projektu (rozpoznawanie głosu), a przy użyciu narzędzia „espeak” brzmiała nieco brytyjsko. I jak kamerdyner lub lokaj. I to jest ostateczny cel: aby ten projekt przerodził się w coś pożytecznego. Tak więc „Wallace”.

Wallace potrafi się poruszać, potrafi omijać przeszkody za pomocą czujników odległości na podczerwień (ostatnio jakoś się usmażyły(?) (trzeba się temu przyjrzeć, jak będę miał okazję), ma też jakieś akustyczne czujniki odległości (trzy zepsuły się w tym samym czasie razem z ekspanderem MCP23017), a na koniec może wykryć zmiany prądu silnika, aby wiedzieć, kiedy w coś uderzy.

Poza czujnikami Wallace „pamięta” 100 ruchów i przeprowadza szczątkową analizę wykorzystującą historię ruchów.

Jak dotąd celem Wallace'a jest po prostu próba poruszania się do przodu i wiedza, kiedy utknął w powtarzającym się wzorze (na przykład w rogu), a nie poruszanie się do przodu.

Przeszedłem przez kilka iteracji dotyczących ruchu i nawigacji, a stały ból głowy pojawia się podczas rotacji.

Ponieważ Wallace jest robotem śledzonym i chciałem, aby wszystko było prostsze w oprogramowaniu (na później), aby się obracać, po prostu obracam go w miejscu. W związku z tym należy zastosować równą, ale przeciwną moc / cykl pracy do silników.

Napotkany problem wynika z konstrukcji platformy robota Agent 390. Pasy gąsienic mają tendencję do ocierania się o boki. A co gorsza, jedna strona robi to więcej niż druga.

Na podłodze i prosto, to nie był problem. Pojawia się na dywanach. Zdecydowałem się trzymać Wallace'a z dala od wykładziny po tym, jak jego ślady stały się brudne (zbierają brud niezwykle łatwo).

Prawdziwym problemem jest obracanie się na podłodze.

Jeśli mam oprogramowanie, które stosuje cykl pracy na wysokim poziomie, to mniej lub bardziej konsekwentnie się obraca. Jednak podczas niskiego cyklu pracy może się obracać lub nie. Albo może się trochę odwrócić, a potem zwolnić. Ruch obrotowy wydaje się być niekontrolowany przez oprogramowanie lub w najlepszym razie bardzo trudny.

Problem pojawia się podczas nawigacji i poruszania się lub oddalania się od przeszkód. Może albo odskoczyć zbyt dziko, albo może utknąć, próbując wykonać bardzo małe zmiany, nawet bez ruchu.

I tak powyższe wyjaśnienie motywowało to Instruktażowe.

Początkowo chciałem zrezygnować lub opóźnić wprowadzenie modułu wykrywającego ruch (IMU), ponieważ są one A) skomplikowane, B) hałaśliwe, C) błędy mogą się z czasem pojawić itd. było to, że możemy zrobić bardzo dobrze, przechodząc do przodu do czujników laserowych na podczerwień czasu lotu. A my mogliśmy - używając laserów, mogliśmy wiedzieć, czy robot się obraca, czy nie, śledząc zmiany odległości.

W rzeczywistości moglibyśmy (tak jakby) zrobić to teraz, za pomocą czujników akustycznych.

Jednak wszystko to jest bardzo pośrednim, skomplikowanym sposobem odpowiedzi na jedno proste pytanie: „czy dokonaliśmy rotacji, czy nie?”

Wydawało mi się, że przeskoczenie do czujników laserowych ToF przeniesie mnie na wyższy poziom oprogramowania; mianowicie SLAM (Simultaneous Localization and Mapping). Nie byłem jeszcze gotowy, żeby tam pojechać.

Dobrze jest zrobić projekt robota w warstwach, przy czym pierwsza (dolna) warstwa jest prostsza, a druga (górna) warstwa jest bardziej abstrakcyjna i zajmuje się trudniejszymi problemami.

Warstwy można wymyślić w taki sposób:

  1. fizyczna rama robota / mechaniczna podstawa konstrukcyjna
  2. podstawowy układ napędowy (Raspberry, Roboclaw, silniki, okablowanie itp., podstawowe oprogramowanie, sterowane klawiaturą)
  3. niezbędne obwody do obsługi czujników (dwukierunkowy przesuwnik napięcia, ekspander portów, zatrzymanie awaryjne, dystrybucja zasilania itp.)
  4. czujniki unikania przeszkód (akustyczne, IR)
  5. niezbędne, podstawowe pozycjonowanie i ruch - detekcja (akcelerometr, żyroskop, magnetometr, enkodery silnika, enkodery koła)

Możesz wymyślić własną listę. Punkty dotyczące tej listy są takie, że prawdopodobnie powinieneś zrobić to mniej więcej w tej kolejności, a także, że jeśli spędzisz trochę czasu na każdej warstwie, aby doprowadzić każdą do dobrego stanu roboczego, to powinno ci pomóc później, gdy sprawy się komplikują.

Powyższa lista może być mniej lub bardziej zmapowana do tych warstw koncepcyjnych w oprogramowaniu.

  • SLAM (jednoczesna lokalizacja i mapowanie)
  • Kontrola i świadomość ruchu, rotacja
  • Podstawowe unikanie przeszkód
  • Kontrola i wykrywanie danych czujnika
  • Niezbędny ruch do przodu, do tyłu, w lewo i w prawo, przyspieszenie, spowolnienie, zatrzymanie

Jak widać, w przypadku tej listy pierwszymi pozycjami byłyby wyższe, bardziej skomplikowane warstwy, które zajmują się bardziej abstrakcyjnymi kwestiami i pytaniami, takimi jak „gdzie jestem” i „dokąd idę”, podczas gdy te ostatnie byłyby niższe warstwy oprogramowania, które obsługują „jak rozmawiać/słuchać czujnika A” lub „jak poruszać tym kołem”.

Teraz nie mówię, że kiedy zaczniesz od warstwy, skończysz ją, a potem jest na następnej warstwie, aby nigdy nie wrócić do poprzedniej. Projekt robota może być bardzo podobny do nowoczesnych, iteracyjnych metod tworzenia oprogramowania (agile, SCRUM itp.).

Mówię tylko, żeby poświęcić czas na każdy. Będziesz musiał zrównoważyć, ile trzeba zrobić w każdym z nich, i zdecydować, co próbujesz na danej warstwie, co jest warte czasu i kłopotów.

Istnieje pewien „konflikt” lub „napięcie” między dwoma konkurującymi ze sobą pomysłami lub kierunkami.

Jednym z nich jest to, co nazwałbym „plug-n-play” w celu rozwiązania problemu A.

Drugi to DIY (zrób to sam). A to może nawet nie być najlepsza etykieta dla tego innego pomysłu.

Oto przykład każdego z nich, miejmy nadzieję, że zobaczysz napięcie lub konflikt między tymi dwoma wyborami.

Na potrzeby tego przykładu połączmy SLAM, unikanie przeszkód i podstawowe podstawowe ruchy jako jeden problem do rozwiązania w tym samym czasie.

  1. Jeśli zdecydujemy się pójść drogą plug-n-play, natychmiast przeskoczymy (w zależności od budżetu) do takich rzeczy, jak te montowane na górze lasery obrotowe, kamera głębi ostrości, lasery ToF i IMU (temat tego Pouczający).
  2. Jeśli natomiast chcemy iść drugą drogą, możemy spróbować wydobyć każdą możliwą informację z niektórych czujników akustycznych lub czujników podczerwieni lub w ogóle ich nie używać - po prostu używamy monitorowania prądu silnika (bump)

Co można powiedzieć o #1 kontra #2? Jedną rzeczą byłoby to, że dzięki #2. Ograniczenia wynikające z posiadania tylko czujników akustycznych do pracy zmuszają nas do zastanowienia się nad znacznie większą liczbą spraw.

Z drugiej strony, jeśli jesteśmy zbyt skupieni na robieniu rzeczy za pomocą #2, możemy tracić czas, ponieważ prosimy o więcej niż powinniśmy od czujników akustycznych.

Jeszcze jedna koncepcja lub pomysł do przemyślenia: jaka mieszanka sprzętu i oprogramowania najlepiej odpowiada na pytania „jak”, a jaka mieszanka oprogramowania (i sprzętu?) odpowiada na pytanie „co”, „kiedy”, „gdzie”. Ponieważ „jak” jest zazwyczaj pytaniem niższego poziomu, od którego zależy „co”, „kiedy” i „gdzie” w celu uzyskania odpowiedzi.

W każdym razie wszystko powyższe było tylko czymś do przemyślenia.

W moim przypadku, po wielu wysiłkach i ciągłym irytującym problemie z tarciem toru i niemożności uzyskania spójnej kontroli i ruchu, nadszedł czas, aby zrobić coś innego.

Tak więc ten Instruktażowy - IMU.

Celem jest to, że jeśli IMU mówi, że robot NIE obraca się, zwiększamy cykl pracy. Jeśli obracamy się zbyt szybko, zmniejszamy cykl pracy.

Krok 1: Czujnik IMU

Czujnik IMU
Czujnik IMU
Czujnik IMU
Czujnik IMU

I tak naszym kolejnym czujnikiem, który dodamy do Wallace'a, jest IMU. Po kilku badaniach zdecydowałem się na MPU6050. Ale w tamtym czasie MPU9050 (a jeszcze niedawno MPU9250) wydawał się jeszcze lepszym pomysłem.

Moim głównym źródłem jest Amazon (w USA). Więc zamówiłem dwa z nich.

To, co dostałem w rzeczywistości (wydaje się, że nie ma nad tym kontroli; tego nie lubię w Amazonie) to dwa MPU92/65. Zastanawiam się trochę nad oznaczeniem. Spójrz na obrazy; to wydaje się być określeniem „rodzinnym”. W każdym razie to jest to, z czym utknąłem.

Dodanie go jest bardzo proste - zdobądź płytkę proto z szynami połączeniowymi, przylutuj czujnik do płytki, dodaj 10-pinową kostkę zacisków śrubowych (ja mam od Pololu).

Aby zminimalizować wszelkie zakłócenia, starałem się umieścić te czujniki z dala od wszystkiego.

Oznaczało to również użycie nylonowych śrub/nakrętek.

Użyję protokołu I2C. Mam nadzieję, że całkowita długość drutu nie będzie taka zła.

Gdzie indziej jest mnóstwo informacji o podstawowych połączeniach, poziomach napięć itp., więc nie będę tego tutaj powtarzał.

Krok 2: Rzeczy nie zawsze są czyste, łatwe

W tej chwili wydaje się, że nie ma zbyt wiele online dla tego konkretnego MPU-92/65. To, co jest dostępne, podobnie jak większość czujników, wydaje się być przykładami wykorzystania Arduino.

Staram się, aby te instrukcje były nieco inne, prezentując niezbyt czysty proces, ponieważ rzeczy nie zawsze działają od razu.

Przypuszczam, że te instrukcje są bardziej podobne do bloga niż proste A-B-C, 1-2-3 „tak to robisz”.

Krok 3: Wstępny test

Test wstępny
Test wstępny
Test wstępny
Test wstępny

Z obrazów w poprzednim kroku czerwone i czarne przewody idące do czujników to oczywiście VCC (5V) i GND. Zielony i żółty przewód to połączenia I2C.

Jeśli wykonałeś inne projekty I2C lub śledziłeś te serie, to wiesz już o "i2cdetect" i to jest pierwszy krok, aby dowiedzieć się, czy Raspberry widzi nowy czujnik.

Jak widać na zdjęciach w tym kroku, nasza pierwsza próba zakończyła się niepowodzeniem. IMU nie pojawia się (powinien być identyfikatorem urządzenia 0x68).

Dobrą wiadomością jest jednak to, że magistrala I2C działa. Widzimy jedno urządzenie 0x20 i jest to ekspander portów MCP23017 (obecnie odpowiedzialny za czujniki akustyczne HCSR04).

Nie jest to łatwe do zobaczenia na obrazku, ale podłączyłem te same kolorowe zielone i żółte przewody z IMU do MCP23017 (patrz lewy dolny obraz)

Będziemy musieli rozwiązać problem.

Krok 4: Rozwiązywanie problemów

Image
Image
Rozwiązywanie problemów
Rozwiązywanie problemów
Rozwiązywanie problemów
Rozwiązywanie problemów

Używając ustawienia ciągłości na woltomierzu (tym z wysokim tonem), przetestowałem połączenia VCC(5V), GND, SDA i SCL. To były dobre.

Następną próbą było odłączenie MCP23017 od magistrali I2C, pozostawiając na magistrali tylko MPU-92/65. Okazało się to bezowocne - "i2cdetect" nie pokazał wtedy żadnych urządzeń.

Więc następnie odmontowałem czujnik z totemu i ponownie podłączyłem go bezpośrednio do dwukierunkowej magistrali 5V-do-3V; czyli prosto do Raspberry. (krótsze przewody?).

I voila. Tym razem jest sukces. Widzimy, że 0x68 pojawia się przy użyciu "i2cdetect".

Ale nie wiemy jeszcze, dlaczego tym razem zadziałało. Czy to może być długość przewodów? Poprzednia lokalizacja?

Uwaga: Nie miało znaczenia, czy ADO było uziemione, czy nie. To może być na pokładzie rezystory pullup i pull-down. To samo może dotyczyć FSYNC.

Następnie ponownie podłączyłem MCP23017. Więc teraz mamy dwa urządzenia na magistrali I2C. (patrz zdjęcie). Sukces, teraz widzimy zarówno 0x20, jak i 0x68 z i2cdetect.

Filmy przedstawiają nieco więcej tego, co wydarzyło się podczas rozwiązywania problemów.

Krok 5: Odczytywanie danych czujnika

Image
Image
Odczytywanie danych czujnika
Odczytywanie danych czujnika
Odczytywanie danych czujnika
Odczytywanie danych czujnika

Różne podejścia

Zdecydowałem się na różne podejścia do uzyskania przydatnych informacji z czujnika. Oto one, nie w dowolnej kolejności:

  1. wypróbuj podstawowe programowanie
  2. przejrzyj dokumentację online dotyczącą rejestrów
  3. spójrz na przykłady i / lub kod innych

Dlaczego takie podejścia? Dlaczego po prostu nie poszukać jakiejś istniejącej biblioteki lub kodu?

Eksperymentując i próbując pewnych pomysłów, możemy lepiej przyswoić sobie wiedzę nie tylko o tym konkretnym czujniku, ale także zdobyć pewną technikę, umiejętności i sposoby myślenia o radzeniu sobie z czymś nowym i czymś, co może nie mieć dużo dokumentacji; coś, co może mieć wiele niewiadomych.

Ponadto, gdy już wypróbowaliśmy i wypróbowaliśmy niektóre z naszych własnych pomysłów i zdobyliśmy trochę wglądu, jesteśmy w lepszej pozycji, aby ocenić czyjś kod lub bibliotekę.

Na przykład, po spojrzeniu na kod C++ dla MPU9250 w github, zdałem sobie sprawę, że zmusza mnie to do użycia przerwań, czego jeszcze nie chcę robić.

Ponadto zawiera dodatkowe rzeczy, takie jak kalibracja; znowu coś, co mnie jeszcze nie interesuje.

Być może to, co muszę zrobić, aby odpowiedzieć na proste pytanie „czy robot obraca się tak lub nie”, można bardzo łatwo odpowiedzieć, po prostu odczytując niektóre rejestry.

Rejestry

W chwili pisania tego tekstu wydaje się, że ten czujnik nie jest zbyt dostępny. W rzeczywistości, jeśli spojrzysz na obrazy dołączone do tej instrukcji i przyjrzysz się bliżej napisom na rzeczywistych żetonach, zastanawiam się, czy to nie jest podróbka. Nie odnoszę tego, co widzę, do niczego z Invense. Niezależnie od tego zdecydowałem się przyjrzeć rejestrom modeli, które znalazłem: MPU-6050 i MPU-9250.

W obu przypadkach poniższe zasady są takie same dla obu. A na początek zakładamy, że będzie tak samo dla tego MPU-92/65.

59 do 64 - pomiary akcelerometrem

65, 66 - pomiary temperatury 67 do 72 - pomiary żyroskopowe 73 do 96 - dane z czujnika zewnętrznego

Uwaga: wydaje się, że MPU-6050 NIE ma magnetometru, podczas gdy MPU-9250 (i zakładamy, że ten też) go ma.

Kilka ciekawszych, miejmy nadzieję przydatnych informacji zebranych z rejestru-dokumentu:

Informacje o magnetometrze:

identyfikator magnetometru: 0x48 rejestry od 00 do 09: 00H WIA 0 1 0 0 1 0 0 0 01H INFO INFO7 INFO6 INFO5 INFO4 INFO3 INFO2 INFO1 INFO0 02H ST1 0 0 0 0 0 0 DOR DRDY 03H HXL HX7 HX6 HX5 HX4 HX3 HX2 04HX1 HX0 HXH HX15 HX14 HX13 HX12 HX11 HX10 HX9 HX8 05H HYL HY7 HY6 HY5 HY4 HY3 HY2 HY1 HY0 06H HYH HY15 HY14 HY13 HY12 HY11 HY10 HY9 HZH1 HZ1 HZL HZ HZ3 HZ2 HZ6 HZ0 07H HZL HZ HZ HZ2 HZ6 HZ ST2 0 0 0 BITM HOFL 0 0 0 podział co oznacza każdy rejestr: HXL[7:0]: niższe dane pomiarowe osi X 8bit HXH[15:8]: wyższe dane pomiarowe osi X 8bit HYL[7:0]: dane pomiarowe osi Y niższe 8bit HYH[15:8]: dane pomiarowe osi Y wyższe 8bit HZL[7:0]: dane pomiarowe osi Z niższe 8bit HZH[15:8]: dane pomiarowe osi Z wyższe 8 bitowy

Programowanie

Inną informacją z dokumentów rejestrów jest to, że wydawało się, że istnieje tylko około 100 rejestrów. Tak więc jedną taktyką może być napisanie prostego programu, który uzyskuje dostęp do urządzenia (0x68) i próbuje sekwencyjnie odczytać serię rejestrów, nie zważając na ich znaczenie, tylko po to, aby zobaczyć, jakie dane można zobaczyć.

A następnie wykonaj kolejne przebiegi, używając tego samego kodu, i porównaj dane z jednego przebiegu z następnym.

Chodzi o to, że prawdopodobnie moglibyśmy wyeliminować wszelkie rejestry, które wydają się nie mieć danych (zera lub FF?) lub które absolutnie nigdy się nie zmieniają, a także moglibyśmy skupić się na tych, które się zmieniają.

Następnie patrzymy tylko na te, które się zmieniają, dodajemy funkcję uśredniania, która uśrednia ostatnie N odczytów tego rejestru, aby zobaczyć, czy rzeczywiście istnieje pewna stała wartość dla tego rejestru. Zakładałoby to, że trzymamy czujnik bardzo nieruchomo iw tym samym miejscu.

Na koniec możemy delikatnie wypróbować czujnik, na przykład popychać go (akcelerometr, żyroskop), dmuchać na niego (temperatura) lub obracać (dwa poprzednie plus magnetometr) i zobaczyć, jaki ma to wpływ na wartości.

Lubię korzystać z biblioteki wirePi tak bardzo, jak to możliwe. Posiada wsparcie dla I2C.

Pierwszy bieg:

/********************************************************************************

* do zbudowania: gcc first.test.mpu9265.c -o first.test.mpu9265 -lwiringPi * * do uruchomienia: sudo./first.test.mpu9265 * * ten program po prostu wypisuje zakres (możliwych) rejestrów z MCP23017, * a następnie z MPU9265 (lub dowolnego innego MPU pod tym adresem 0x68) * * Użyłem go do sprawdzenia, czy mogę nawet odczytać z czujnika, ponieważ już * miałem zaufanie do MCP23017. * ************************************************** ****************************/ #include #include #include #include #include int main(int argc, char** argv) { puts("Zobaczmy, co MCP23017 @ 0x20 ma do powiedzenia:"); błąd = 0; int deviceId1 = 0x20; int fd1 = okablowaniePiI2CSetup(deviceId1); if (-1 == fd1) { fprintf (stderr, "Nie można otworzyć urządzenia okablowaniaPi I2C: %s\n", strerror (errno)); powrót 1; } for (int reg=0;reg<300;reg++) { fprintf(stderr, "%d", okablowaniePiI2CReadReg8(fd1, reg));fflush(stderr); opóźnienie(10); } puts(""); puts("Zobaczmy, co MPU9265 @ 0x20 ma do powiedzenia:"); błąd = 0; int identyfikatorurządzenia2 = 0x68; int fd2 = okablowaniePiI2CSetup(deviceId2); if (-1 == fd2) { fprintf (stderr, "Nie można otworzyć urządzenia okablowaniaPi I2C: %s\n", strerror (errno)); powrót 1; } for (int reg=0;reg<300;reg++) { fprintf(stderr, "%d", okablowaniePiI2CReadReg8(fd2, reg));fflush(stderr); opóźnienie(10); } puts(""); zwróć 0; }

Drugi bieg:

/********************************************************************************

* do zbudowania: gcc second.test.mpu9265.c -o second.test.mpu9265 -lwiringPi * * do uruchomienia: sudo./second.test.mpu9265 * * Ten program wyświetla numer rejestru obok odczytanej wartości. * * To sprawia, że przydatne jest potokowanie (przekierowanie) wyjścia do pliku, a następnie * można wykonać kilka przebiegów w celu porównania. Może to dać pewien wgląd * w to, jakie rejestry są ważne i jak mogą się zachowywać dane. * ************************************************** ****************************/ #include #include #include #include #include #include int main(int argc, char** argv) { int identyfikator urządzenia = -1; if (0) { } else if (!strncmp(argv[1], "0x20", strlen("0x20"))) { deviceId = 0x20; } else if (!strncmp(argv[1], "0x68", strlen("0x68"))) { deviceId = 0x68; } else if (!strncmp(argv[1], "0x69", strlen("0x69"))) { deviceId = 0x69; } puts("Zobaczmy, co MPU9265 @ 0x20 ma do powiedzenia:"); błąd = 0; int fd = okablowaniePiI2CSetup(deviceId); if (-1 == fd) { fprintf (stderr, "Nie można otworzyć urządzenia okablowaniaPi I2C: %s\n", strerror (errno)); powrót 1; } for (int reg=0;reg<300;reg++) { fprintf(stderr, "%d:%d\n", reg, wirePiI2CReadReg8(fd, reg));fflush(stderr); opóźnienie(10); } zwróć 0; }

Trzeci bieg:

/********************************************************************************

* do zbudowania: gcc third.test.mpu9265.c -o third.test.mpu9265 -lwiringPi * * do uruchomienia: sudo./third.test.mpu9265 * * Ten program jest wynikiem działania drugiego. Odczytuje tylko z rejestrów *, które wskazują różnicę między jednym przebiegiem a następnym.* ************************************************** ****************************/ #include #include #include #include #include #include int main(int argc, char** argv) { int identyfikator urządzenia = -1; if (0) { } else if (! strncmp(argv[1], "0x68", strlen("0x68"))) { deviceId = 0x68; } else if (!strncmp(argv[1], "0x69", strlen("0x69"))) { deviceId = 0x69; } puts("Zobaczmy, co MPU9265 @ 0x20 ma do powiedzenia:"); błąd = 0; int fd = okablowaniePiI2CSetup(deviceId); if (-1 == fd) { fprintf (stderr, "Nie można otworzyć urządzenia okablowaniaPi I2C: %s\n", strerror (errno)); powrót 1; } for (int reg=61;reg<=73;reg++) { fprintf(stderr, "%d:%d\n", reg, wirePiI2CReadReg8(fd, reg));fflush(stderr); opóźnienie(10); } for (int reg=111;reg<=112;reg++) { fprintf(stderr, "%d:%d\n", reg, wirePiI2CReadReg8(fd, reg));fflush(stderr); opóźnienie(10); } for (int reg=189;reg<=201;reg++) { fprintf(stderr, "%d:%d\n", reg, wirePiI2CReadReg8(fd, reg));fflush(stderr); opóźnienie(10); } for (int reg=239;reg<=240;reg++) { fprintf(stderr, "%d:%d\n", reg, wirePiI2CReadReg8(fd, reg));fflush(stderr); opóźnienie(10); } zwróć 0; }

Czego więc nauczyliśmy się do tej pory? Obraz tabeli z kolorowymi podświetlonymi obszarami wskazuje, że wynik wydaje się pasować do pierwszych zestawów rejestrów.

Dotychczasowe wyniki mogą generować nowe pytania.

Pytanie: dlaczego istnieje tylko jeden wynik rejestru dla grupy „zewnętrznej”?

Pytanie: czym są te wszystkie nieznane rejestry "???????"

Pytanie: skoro program nie jest sterowany przerwaniami, czy żądał danych zbyt wolno? za szybko?

Pytanie: czy możemy wpłynąć na wyniki, próbując różnych rzeczy z samym czujnikiem podczas jego działania?

Krok 6: Zagłębmy się w odczyty/dane

Myślę, że następnym krokiem przed czymkolwiek innym jest ulepszenie programu, aby:

  • być elastycznym w zakresie opóźnienia pętli (ms)
  • być elastycznym w zakresie liczby odczytów, aby uzyskać średnią bieżącą na rejestr

(Musiałem dołączyć program jako plik. Wydawało się, że problem z wstawieniem go tutaj. "fourth.test.mpu9265.c")

Oto przebieg wykorzystujący średnio 10 ostatnich odczytów w pętli 10 ms:

sudo./czwarty.test.mpu9265 0x68 10 10

61:255 0 255 0 255 0 255 0 0 0: 102 62:204 112 140 164 148 156 188 248 88 228: 167 63:189 188 189 187 189 188 188 188 188 189: 188 64: 60 40 16 96 208 132 116 252 172 36: 112 65: 7 7 7 7 7 7 7 7 7 7: 7 66:224 224 224 240 160 208 224 208 144 96: 195 67: 0 0 0 0 0 0 0 0 0 0: 0 68:215 228 226 228 203 221 239 208 214 187: 216 69: 0 255 0 255 255 0 255 0 0 0: 102 70:242 43 253 239 239 45 206 28 247 207: 174 71: 0 255 255 0 255 255 255 255 255 255: 204 72: 51 199 19 214 11 223 21 236 193 8: 117 73: 0 0 0 0 0 0 0 0 0 0: 0 111: 46 149 91 199 215 46 142 2 233 199: 132 112: 0 0 0 0 0 0 0 0 0 0: 0 189:255 0 255 0 255 0 0 255 0 255: 127 190: 76 36 240 36 100 0 164 164 152 244: 121 191:188 188 188 188 187 188 187 189 187 189: 187 192: 8 48 48 196 96 220 144 0 76 40: 87 193: 7 7 7 7 7 8 7 7 7 7: 7 194:208 224 144 240 176 240 224 208 240 224: 212 195: 0 0 0 0 0 0 0 0 0 0: 0 196:243 184 233 200 225 192 189 242 188 203: 209 197:255 0 0 0 255 0 255 0 0 255: 102 198:223 39 247 43 245 22 255 221 0 6: 130 199: 0 255 255 255 0 255 255 255 255 0: 178 200:231 225 251 1 252 20 211 216 218 16: 164 201: 0 0 0 0 0 0 0 0 0 0: 0 239: 21 138 196 87 26 89 16 245 187 144: 114 240: 0 0 0 0 0 0 0 0 0 0: 0

Pierwsza, skrajna od lewej kolumna to numer rejestru. Następnie przyjdź ostatnie 10 odczytów dla tego rejestru. Wreszcie ostatnia kolumna to średnia dla każdego wiersza.

Wygląda na to, że rejestry 61, 69, 71, 189, 197 i 199 są albo tylko binarne, albo gotowe/niegotowe, albo mają wysoki bajt wartości 16-bitowej (ujemne?).

Inne ciekawe spostrzeżenia:

  • rejestry 65, 193 - bardzo stabilna i ta sama wartość
  • rejestr 63, 191 - bardzo stabilna i ta sama wartość
  • rejestry 73, 112, 195, 201, 240 - wszystkie na zero

Odnieśmy te obserwacje z powrotem do wielokolorowego, podświetlonego obrazu tabeli z wcześniej.

Rejestr 65 - temperatura

Zarejestruj się 193 - ??????

Rejestr 63 - akcelerometr

Zarejestruj się 191 - ??????

Zarejestruj się 73 - zewnętrzne

Zarejestruj 112 i dalej - ??????

Cóż, wciąż mamy niewiadome, jednak nauczyliśmy się czegoś przydatnego.

Rejestr 65 (temperatura) i rejestr 63 (akcelerometr) były bardzo stabilne. To jest coś, czego byśmy się spodziewali. nie dotknąłem czujnika; nie porusza się, poza przypadkowymi wibracjami, ponieważ robot spoczywa na tym samym stole, co mój komputer.

Dla każdego z tych rejestrów temperatury/akcelerometru możemy wykonać jeden interesujący test. Do tego testu potrzebujemy jeszcze innej wersji programu.

Krok 7: Jesteśmy w stanie wpływać na temperaturę i przyspieszenie

W poprzednich krokach zawęziliśmy co najmniej jeden rejestr dla temperatury i jeden dla przyspieszenia.

W kolejnej wersji programu ("fifth.test.mpu9265.c") widzimy zmianę zachodzącą w obu rejestrach. Proszę obejrzeć filmy.

Więcej kopania

Jeśli cofniemy się i spojrzymy na informacje z rejestru, zobaczymy, że są:

  • trzy 16-bitowe wyjścia dla żyroskopu
  • trzy 16-bitowe wyjścia dla akcelerometru
  • trzy 16-bitowe wyjścia dla magnetometru
  • jedno wyjście 16-bitowe dla temperatury

Jednak wszystkie wyniki uzyskane przez nasze proste programy testowe były pojedynczymi 8-bitowymi wyjściami. (pojedyncze rejestry).

Spróbujmy więc więcej tego samego podejścia, ale tym razem czytając 16 bitów zamiast 8.

Prawdopodobnie będziemy musieli zrobić coś takiego jak poniżej. Użyjmy temperatury jako przykładu, ponieważ jest to tylko jedno wyjście 16-bitowe.

//uzyskaj deskryptor pliku fd…

int tempRegHi = 65; int tempRegLo = 66; int hiByte = okablowaniePiI2CReadReg8(fd, tempRegHi); int loByte = okablowaniePiI2CReadReg8(fd, tempRegLo); int wynik = hiByte << 8; // wstaw 8 bitów hi order w górnej części 16-bitowej wartości wyniku |= loByte; // teraz dodaj 8 bitów w kolejności lo, otrzymując pełną 16-bitową liczbę // wydrukuj tę liczbę lub użyj funkcji wyświetlania wykresów poziomych z wcześniej

Z naszych poprzednich kroków widzieliśmy, że rejestr 65 jest dość stabilny, podczas gdy rejestr 66 jest bardzo głośny. Ponieważ 65 to bajt wysokiego rzędu, a 66 to bajt niskiego rzędu, ma to sens.

Do odczytu możemy pobrać dane z rejestru 65 bez zmian, ale możemy uśrednić wartości rejestru 66.

Albo możemy po prostu uśrednić cały wynik.

Spójrz na ostatni film z tej części; pokazuje odczyt całej 16-bitowej wartości temperatury. Kod to „szósty.test.mpu9265.c”

Krok 8: Akcelerometr i żyroskop

Image
Image

Filmy wideo do tej sekcji pokazują dane wyjściowe z akcelerometru i żyroskopu przy użyciu programu testowego „seventh.test.mpu9265.c”. Ten kod może odczytywać 1, 2 lub 3 kolejne pary bajtów (bajty hi i lo) i konwertować wartości na pojedynczą wartość 16-bitową. W ten sposób możemy odczytać dowolną pojedynczą oś lub możemy odczytać dwie z nich razem (i sumuje zmiany) lub możemy odczytać wszystkie trzy (i sumuje zmiany).

Aby powtórzyć, w tej fazie, w tym Instruktażowym, chcę tylko odpowiedzieć na proste pytanie: „czy robot się obracał / obracał?”. Nie szukam dokładnej wartości, np. czy obrócił się o 90 stopni. To przyjdzie później, gdy zaczniemy robić SLAM, ale nie jest to wymagane do prostego unikania przeszkód i przypadkowego ruchu.

Krok 9: (praca w toku) magnetometr

podczas korzystania z narzędzia i2cdetect, MPU9265 wyświetla się w tabeli jako 0x68:

0 1 2 3 4 5 6 7 8 9 a b c d e f

00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

Do odczytu z części magnetometru IMU wymagane są dodatkowe kroki.

Z dokumentu PDF rejestrów Invesense:

REJESTRY 37 DO 39 – STEROWANIE I2C SLAVE 0

  • REJESTRACJA 37 - I2C_SLV0_ADDR
  • REJESTRACJA 38 - I2C_SLV0_REG
  • REJESTRACJA 39 - I2C_SLV0_CTRL

Zalecana: