Multiwii and Megapirate AIO Flight Controller w/FTDI (ATmega 2560) V2.0
ID: 77
Kategorie: CPU
Menge: 0
Position:

Opis

Kontroler lotu wyposażony w 3-osiowy żyroskop i akcelerometr, 3-osiowy magnetometr oraz barometr. CaÅ‚ość sterowana mikrokontrolerem ATmega 2560 znanym z Arduino Mega. Posiada 8 wejść odbiornika, wyjÅ›cia do podÅ‚Ä…czenia serwomechanizmów oraz interfejsy: UART, I2C i analogowe.

 

Specyfikacja

  • Wsparcie dla oprogramowania MegaPirateNG oraz MultiWii
  • Wbudowany regulator napiÄ™cia 3,3 V i 5 V
  • Mikrokontroler ATmega 2560 kompatybilny z Arduino Mega
  • Wbudowany moduÅ‚ MPU-6050 akcelerometr i żyroskop (dokumentacja)
    • Trzy osie: X, Y, Z
    • Interfejs komunikacyjny: I2C (TWI) - 400 kHz
    • Rozdzielczość: 16-bitów dla każdej osi
    • Zakresy pomiarowe (konfigurowalne):
      • Akcelerometr: ±2g, ±4g, ±8g, ±16g
      • Å»yroskop: ±250, ±500, ±1000, ±2000 °/s
  • Wbudowany moduÅ‚ HMC5883L: 3-osiowy cyfrowy magnetometr (dokumentacja)
    • Trzy osie: X, Y, Z
    • Interfejs komunikacyjny: I2C (TWI)
    • Rozdzielczość: 12 bitów dla każdej osi - 5 mili gaus
    • Zakres pomiarowy (konfigurowalny): ±8 gaus
  • Wbudowany moduÅ‚ MS5611-01BA01 wysokoÅ›ciomierz wysokiej precyzji (dokumentacja)
    • Zakres pomiarowy: od 10 do 1200 mbar
    • Rozdzielczość: 2 bitów
  • Wbudowany konwerter poziomów logicznych
  • 8 kanaÅ‚ów wejÅ›ciowych dla standardowych odbiorników RC
  • 4 porty szeregowe UART dla debugowania / moduÅ‚u Bluetooth / OSD / GPS / telemetrii
  • Wyprowadzone zÅ‚Ä…cza interfejsu I2C dla zewnÄ™trznego urzÄ…dzenia lub czujnika
  • 2 wyjÅ›cia dla serw do gimbala
  • 1 wyjÅ›cie dla serwa do przycisku aparatu
  • 6 analogowych wyjść dla urzÄ…dzeÅ„ zewnÄ™trznych

 

W zestawie

  • Kontroler lotu 
  • Przewód żęńsko-żęński - 100 mm - 9 szt.
  • Przewód 3-pin na 3-pin - 100 mm - 1 szt.
  • Przewód molex 1,25 mm 4-pinowy - 1 szt.
  • Przewód molex 1,25 mm 6-pinowy - 2 szt.
  • Przewód molex 1,25 mm 8-pinowy - 1 szt.

 

Przydatne linki


3-osiowy magnetometr HMC5883L

HMC5883L jest cyfrowym, 3-osiowym magnetometrem pozwalajÄ…cym na pomiar szerokiego zakresu wielkoÅ›ci pola magnetycznego Ziemi wynoszÄ…cego ±8 gausa. Jego rozdzielczość 12 bitów umożliwia pomiar z dokÅ‚adnoÅ›ciÄ… do 2 miligausów przy poborze prÄ…du zaledwie 100µAHMC5883L komunikuje siÄ™ z mikrokontrolerem za pomocÄ… szyny I2C z maksymalnÄ… czÄ™stotliwoÅ›ciÄ… pomiarów wynoszÄ…cÄ… 75 Hz w trybie ciÄ…gÅ‚ym. 

 

Zakres pomiarowy Rozdzielczość Wzmocnienie
± 0.88 Ga 0.73 mG 1370
± 1.3 Ga 0.92 mG 1090
± 1.9 Ga 1.22 mG 820
± 2.5 Ga 1.52 mG 660
± 4 Ga 2.27 mG 440
± 4.7 Ga 2.56 mG 390
± 5.6 Ga 3.03 mG 330
± 8.1 Ga 4.35 mG 230

HMC5883L pozwala na osiÄ…gniÄ™cie czÄ™stotliwoÅ›ci pomiarów nawet do 160 Hz, jeÅ›li skorzystamy z trybu pojedyÅ„czego pomiaru oraz monitorowania przerwania DRDY. CiekawÄ… możliwoÅ›ciÄ… jakÄ… daje ten ukÅ‚ad, to wybór iloÅ›ci próbek (1, 2, 4 lub 8), które podlegajÄ… uÅ›rednieniu koÅ„cowego wyniku.

NapiÄ™cie zasilania mieÅ›ci siÄ™ w zakresie od 2.0 do 3.6V, dlatego ukÅ‚ad również nie toleruje zasilania wyższego (5V) - należy zwrócić szczególnÄ… uwagÄ™ na to, czy nasz moduÅ‚ posiada możliwość zasilania takim napiÄ™ciem. UkÅ‚ad jest zamkniÄ™ty w obudowie LCC o wymiarach 3mm x 3mm i wysokoÅ›ci 0.91mm .

PeÅ‚na dokumentacja techniczna: http://www.jarzebski.pl/datasheets/HMC5883L.pdf

Podłączenie HMC5883L do Arduino

W przypadku moduÅ‚ IMU GY-80, możemy skorzystać z 5V zasilania. Pin oznaczony SCL (adapter) podÅ‚Ä…czamy do pinu A5 (Arduino), natomiast pin SDA (adapter) do pinu A4 (Arduino).

Do obsÅ‚ugi moduÅ‚ów z ukÅ‚adami HMC5883L skorzystamy z  przygotowanej na tÄ… okazjÄ™ biblioteki  dla Arduino, którÄ… można pobrać z repozytorium Githttps://github.com/jarzebski/Arduino-HMC5883L

Prosty przykład

Pierwszym przykładem będzie odczyt surowych wartości oraz znormalizowanych (mg):

  1. #include <Wire.h>
  2. #include <HMC5883L.h>
  3.  
  4. HMC5883L compass;
  5.  
  6. void setup()
  7. {
  8.   Serial.begin(9600);
  9.  
  10.   // Inicjalizacja HMC5883L
  11.   Serial.println("Initialize HMC5883L");
  12.   while (!compass.begin())
  13.   {
  14.     Serial.println("Nie odnaleziono HMC5883L, sprawdz polaczenie!");
  15.     delay(500);
  16.   }
  17.  
  18.   // Ustawienie zakresu pomiarowego
  19.   // +/- 0.88 Ga: HMC5883L_RANGE_0_88GA
  20.   // +/- 1.30 Ga: HMC5883L_RANGE_1_3GA (domyslny)
  21.   // +/- 1.90 Ga: HMC5883L_RANGE_1_9GA
  22.   // +/- 2.50 Ga: HMC5883L_RANGE_2_5GA
  23.   // +/- 4.00 Ga: HMC5883L_RANGE_4GA
  24.   // +/- 4.70 Ga: HMC5883L_RANGE_4_7GA
  25.   // +/- 5.60 Ga: HMC5883L_RANGE_5_6GA
  26.   // +/- 8.10 Ga: HMC5883L_RANGE_8_1GA
  27.   compass.setRange(HMC5883L_RANGE_1_3GA);
  28.  
  29.   // Ustawienie trybu pracy
  30.   // Uspienie:              HMC5883L_IDLE
  31.   // Pojedynczy pomiar:     HMC5883L_SINGLE
  32.   // Ciagly pomiar: HMC5883L_CONTINOUS (domyslny)
  33.   compass.setMeasurementMode(HMC5883L_CONTINOUS);
  34.  
  35.   // Ustawienie czestotliwosci pomiarow
  36.   //  0.75Hz: HMC5883L_DATARATE_0_75HZ
  37.   //  1.50Hz: HMC5883L_DATARATE_1_5HZ
  38.   //  3.00Hz: HMC5883L_DATARATE_3HZ
  39.   //  7.50Hz: HMC5883L_DATARATE_7_50HZ
  40.   // 15.00Hz: HMC5883L_DATARATE_15HZ (domyslny)
  41.   // 30.00Hz: HMC5883L_DATARATE_30HZ
  42.   // 75.00Hz: HMC5883L_DATARATE_75HZ
  43.   compass.setDataRate(HMC5883L_DATARATE_15HZ);
  44.  
  45.   // Liczba usrednionych probek
  46.   // 1 probka:  HMC5883L_SAMPLES_1 (domyslny)
  47.   // 2 probki: HMC5883L_SAMPLES_2
  48.   // 4 probki: HMC5883L_SAMPLES_4
  49.   // 8 probki: HMC5883L_SAMPLES_8
  50.   compass.setSamples(HMC5883L_SAMPLES_1);
  51. }
  52.  
  53. void loop()
  54. {
  55.   // Pobranie pomiarow surowych
  56.   Vector raw = compass.readRaw();
  57.  
  58.   // Pobranie pomiarow znormalizowanych
  59.   Vector norm = compass.readNormalize();
  60.  
  61.   // Wyswielnie wynikow
  62.   Serial.print(" Xraw = ");
  63.   Serial.print(raw.XAxis);
  64.   Serial.print(" Yraw = ");
  65.   Serial.print(raw.YAxis);
  66.   Serial.print(" Zraw = ");
  67.   Serial.print(raw.ZAxis);
  68.   Serial.print(" Xnorm = ");
  69.   Serial.print(norm.XAxis);
  70.   Serial.print(" Ynorm = ");
  71.   Serial.print(norm.YAxis);
  72.   Serial.print(" ZNorm = ");
  73.   Serial.print(norm.ZAxis);
  74.   Serial.println();  
  75.  
  76.   delay(100);
  77. }

Wynik działania

HMC5883L jako kompas cyfrowy

Znajomość wartości pola magnetycznego Ziemi (wektor X i wektor Y) pozwala na określenie bieżącego kierunku południka magnetycznego, a tym samym uzyskanie cyfrowego kompasu. Kierunek południka magnetycznego można obliczyć z prostej zależności:

kierunek_pomiaru (rad) = atan( wektor_y, wektor_x );

Aby  poprawnie wyznaczyć kierunek, konieczne jest również uwzglÄ™dnienie czynnika bÅ‚Ä™du - deklinacji magnetycznej. Deklinacja magnetyczna spowodowana jest zarówno poÅ‚ożeniem bieguna magnetycznego Ziemi w innym miejscu niż biegun geograficzny oraz zróżnicowanymi warunkami magnetycznymi w miejscu pomiaru (np. poprzez wystÄ™powaniem dużej iloÅ›ci rud żelaza). Warto zauważyć, że deklinacja magnetyczna jest parametrem zmiennym w czasie, bowiem biegun magnetyczny Ziemi stale siÄ™ przemieszcza. Wartość aktualnej deklinacji magnetycznej znajdziemy na specjalnych mapach magnetycznych, a także na mapach nawigacyjnych.

Na szczęście żyjemy w czasach Internetu i odpowiedniÄ… mapÄ™ znajdziemy pod adresem: http://magnetic-declination.com/

Deklinacja magnetyczna dla Bytomia

Jak widzimy, deklinacja magnetyczna dla mojej lokalizacji wynosi plus 4 stopnie i 26 minut (wschód). Wartość tÄ… musimy przeliczyć na radiany:

kÄ…t_deklinacji = (stopnie + (minuty / 60.0)) / (180 / Pi);
kÄ…t_deklinacji = (4.0 + (26.0 / 60.0)) / (180 / Pi);

Obliczoną wartość kąta deklinacji dodajemy (wynik POSITIVE) lub odejmujemy (wynik NEGATIVE) od wartości zmierzonej z magnetometru:

kierunek = kierunek_pomiaru ± kÄ…t_deklinacji

JeÅ›li nie znamy kÄ…ta deklinacji, możemy przyjąć wartość zero. W nastÄ™pnej kolejnoÅ›ci musimy zadbać o to, aby otrzymany wynik kierunku bieguna magnetycznego mieÅ›ciÅ‚ siÄ™ w zakresie 0π - 2π (chyba, że chcemy mieć kompas, który pokazuje na przykÅ‚ad 370° zamiast 10°).

jeÅ›li kierunek < 0 to dodajemy do niego 2π
jeÅ›li kierunek > 2π to odejmujemy od niego 2π

Teraz możemy zamienić już radiany na stopnie:

kierunek (deg) = kierunek (rad) * (180 / π)

Istotnym problemem (brzydkÄ… cechÄ…) magnetometru HMC5883L jest nierównomierny pomiar pola magnetycznego w zakresie od 1° ÷ 180° oraz od 180° ÷ 360°. Dla pierwszego przedziaÅ‚u nasz magnetometr bÄ™dzie generowaÅ‚ przekÅ‚amane wyniki od 1° ÷ 240°, natomiast dla drugiego  od 240° ÷ 360°. Można w Å‚atwy sposób to skorygować funkcjÄ… map() (patrz poniższy przykÅ‚ad programu). Do peÅ‚ni szczęścia możemy jeszcze wygÅ‚adzić wskazania naszego kompasu, ustawiajać jego reakcjÄ™ na zmianÄ™ o 3°.

Nasz program przedstawia się więc następująco:

  1. #include <Wire.h>
  2. #include <HMC5883L.h>
  3.  
  4. HMC5883L compass;
  5.  
  6. int previousDegree;
  7.  
  8. void setup()
  9. {
  10.   Serial.begin(9600);
  11.  
  12.   // Inicjalizacja HMC5883L
  13.   Serial.println("Initialize HMC5883L");
  14.   while (!compass.begin())
  15.   {
  16.     Serial.println("Nie odnaleziono HMC5883L, sprawdz polaczenie!");
  17.     delay(500);
  18.   }
  19.  
  20.   // Ustawienie zakresu pomiarowego
  21.   compass.setRange(HMC5883L_RANGE_1_3GA);
  22.  
  23.   // Ustawienie trybu pracy
  24.   compass.setMeasurementMode(HMC5883L_CONTINOUS);
  25.  
  26.   // Ustawienie czestotliwosci pomiarow
  27.   compass.setDataRate(HMC5883L_DATARATE_15HZ);
  28.  
  29.   // Liczba usrednionych probek
  30.   compass.setSamples(HMC5883L_SAMPLES_4);
  31. }
  32.  
  33. void loop()
  34. {
  35.   // Pobranie wektorów znormalizowanych
  36.   Vector norm = compass.readNormalize();
  37.  
  38.   // Obliczenie kierunku (rad)
  39.   float heading = atan2(norm.YAxis, norm.XAxis);
  40.  
  41.   // Ustawienie kata deklinacji dla Bytomia 4'26E (positive)
  42.   // Formula: (deg + (min / 60.0)) / (180 / M_PI);
  43.   float declinationAngle = (4.0 + (26.0 / 60.0)) / (180 / M_PI);
  44.   heading += declinationAngle;
  45.  
  46.   // Korekta katow
  47.   if (heading < 0)
  48.   {
  49.     heading += 2 * PI;
  50.   }
  51.  
  52.   if (heading > 2 * PI)
  53.   {
  54.     heading -= 2 * PI;
  55.   }
  56.  
  57.   // Zamiana radianow na stopnie
  58.   float headingDegrees = heading * 180/M_PI;
  59.  
  60.   // Output
  61.   Serial.print(" Heading = ");
  62.   Serial.print(heading);
  63.   Serial.print(" Degress = ");
  64.   Serial.print(headingDegrees);
  65.   Serial.println();
  66.  
  67.   delay(100);
  68.  
  69.   delay(100);
  70. }

Wynik działania:

Program do processingu znajdziecie w archwium biblioteki.

Uwaga na koniec

Niestety kompas jest  wrażliwy na wszelkie przechylenia, faÅ‚szujÄ…c kalkulacjÄ™ kierunku poÅ‚udnika magnetycznego. Musi siÄ™ wiÄ™c znajdować na pÅ‚askiej powierzchni, aby wyniki byÅ‚y poprawne. Niepożądany efekt wpÅ‚ywu przechyleÅ„ można na szczęście wyeliminować za pomocÄ… akcelerometru (na przykÅ‚ad ADXL345 lub MPU6050). Jak tego dokonać? Dowiesz siÄ™ z tego artykuÅ‚u - Komepnsacja przechyleÅ„ kompasów cyfrowych.

Demo

 

Materiały dodatkowe

Biblioteka HMC5883Lhttps://github.com/jarzebski/Arduino-HMC5883L
Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/HMC5883L.pdf


3-osiowy żyroskop i akcelerometr MPU6050

MPU6050 jest ukÅ‚adem, który Å‚Ä…czy w sobie 3-osiowy żyroskop, 3-osiowy akcelerometr oraz cyfrowy termometr. Z powodzeniem może zastÄ…pić opisywane już wczeÅ›niej ukÅ‚ady ADXL345 oraz L3G4200D. Jego szczególnÄ… cechÄ… jest wbudowana sprzÄ™towa jednostka DMP (Digital Motion Processor), która uÅ‚atwia przeliczanie przetwarzanych danych z wszystkich trzech czujników na konkretne poÅ‚ożenie wzglÄ™dem Ziemi, odciążajÄ…c tym samym mikrokontroler. JednostkÄ™ DMP można zaprogramować tak, aby wykorzystywaÅ‚a do swoich obliczeÅ„ również zewnÄ™trzny magnetometr.

 

W odróżnieniu od opisywanego już żyroskopu L3G4200D, oprócz możliwoÅ›ci pracy w zakresach pomiarowych ±250°/s, ±500°/s oraz ±2000°/s posiada dodatkowy tryb ±1000°/s, co czyni go bardziej uniwersalnym rozwiÄ…zaniem. Za przetwarzanie danych odpowiada również 16 bitowy przetwornik. PrzewagÄ… MPU6050 nad ADXL345 jest również dokÅ‚adniejszy 16-bitowy przetwornik zamiast 13-bitowego. Praktycznie MPU6050 posiada takie same funkcje jak ADXL345 oraz L3G4200D, jednak rozszerza swoje wÅ‚aÅ›ciwoÅ›ci o programowalny filtr dolnoprzepustowy, dodatkowÄ… szynÄ™ do komunikacji z innymi ukÅ‚adami oraz dodatkowe tryby oszczÄ™dzania energii. Wszystko to przy maksymalnym poborze prÄ…du 4.1mA (w duecie L3G4200D oraz ADXL345 potrafi przekroczyć 6mA)

NapiÄ™cie zasilania może mieÅ›cić siÄ™ w zakresie od 2.375V ÷ 3.46V, natomiast poziomy logiczne mogÄ… mieÅ›cić siÄ™ w zakresie od 1.71V do wartoÅ›ci napiÄ™cia zasilania

Wyprowadzania linii układu oraz orientacja osi

Podłączenie MPU6050 do Arduino

UkÅ‚ad MPU6050 toleruje zasilanie z przedziaÅ‚u 2.375V ÷ 3.46V, wiÄ™c jeÅ›li planujemy podÅ‚Ä…czyć go do Arduino UNO, nie zapomnijmy o konwerterze napięć poziomów logicznych. W przypadku moduÅ‚u IMU GY-86 oraz IMU GY-87, możemy skorzystać z 5V zasilania. Pin oznaczony SCL (adapter) podÅ‚Ä…czamy do pinu A5 (Arduino), natomiast pin SDA (adapter) do pinu A4 (Arduino). W moim ukÅ‚adzie wykorzystaÅ‚em również dwie diody z rezystorami 220Ω, sterowane wyjÅ›ciami cyfrowymi Arduino (4,7) do sygnalizacji przerwaÅ„.

Do obsÅ‚ugi moduÅ‚ów z ukÅ‚adami MPU6050 przygotowaÅ‚em również odpowiedniÄ… do nich bibliotekÄ™ dla Arduino, którÄ… można pobrać z repozytorium Githttps://github.com/jarzebski/Arduino-MPU6050

Odczyt danych z żyroskopu

Odczyt z żyroskopu realizowany jest w podobny sposób jak w L3G4200D. Mamy możliwość odczytu danych bezpoÅ›rednich za pomocÄ… funkcji readRawGyro() oraz przeliczonych na jednostkÄ™ dps za pomocÄ… funkcji readNormalizeGyro(). Praktycznie jedynÄ… różnicÄ… jest inicjalizacja ukÅ‚adu, gdzie konfigurujemy jednoczeÅ›nie akcelerometr jak i żyroskop.

  1. #include <Wire.h>
  2. #include <MPU6050.h>
  3.  
  4. MPU6050 mpu;
  5.  
  6. void setup()
  7. {
  8.   Serial.begin(115200);
  9.  
  10.   Serial.println("Inicjalizacja MPU6050");
  11.   while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  12.   {
  13.     Serial.println("Nie mozna znalezc MPU6050 - sprawdz polaczenie!");
  14.     delay(500);
  15.   }
  16.  
  17.   // Kalibracja żyroskopu
  18.   mpu.calibrateGyro();
  19.  
  20.   // Ustawienie czułości
  21.   mpu.setThreshold(3);
  22. }
  23.  
  24. void loop()
  25. {
  26.   Vector rawGyro = mpu.readRawGyro();
  27.   Vector normGyro = mpu.readNormalizeGyro();
  28.  
  29.   Serial.print(" Xraw = ");
  30.   Serial.print(rawGyro.XAxis);
  31.   Serial.print(" Yraw = ");
  32.   Serial.print(rawGyro.YAxis);
  33.   Serial.print(" Zraw = ");
  34.   Serial.println(rawGyro.ZAxis);
  35.  
  36.   Serial.print(" Xnorm = ");
  37.   Serial.print(normGyro.XAxis);
  38.   Serial.print(" Ynorm = ");
  39.   Serial.print(normGyro.YAxis);
  40.   Serial.print(" Znorm = ");
  41.   Serial.println(normGyro.ZAxis);
  42.  
  43.   delay(10);
  44. }

Odczyt danych z akcelerometru

W przypadku odczytu danych z akcelerometru, analogicznie posÅ‚ugujemy siÄ™ funkcjami readRawAccel() oraz readNormalizeAccel(). ZnormalizowanÄ… jednostkÄ… sÄ… tutaj m/s.

  1. #include <Wire.h>
  2. #include <MPU6050.h>
  3.  
  4. MPU6050 mpu;
  5.  
  6. void setup()
  7. {
  8.   Serial.begin(115200);
  9.  
  10.   Serial.println("Inicjalizacja MPU6050");
  11.  
  12.   while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  13.   {
  14.     Serial.println("Nie mozna znalezc MPU6050 - sprawdz polaczenie!");
  15.     delay(500);
  16.   }
  17. }
  18.  
  19. void loop()
  20. {
  21.   Vector rawAccel = mpu.readRawAccel();
  22.   Vector normAccel = mpu.readNormalizeAccel();
  23.  
  24.   Serial.print(" Xraw = ");
  25.   Serial.print(rawAccel.XAxis);
  26.   Serial.print(" Yraw = ");
  27.   Serial.print(rawAccel.YAxis);
  28.   Serial.print(" Zraw = ");
  29.  
  30.   Serial.println(rawAccel.ZAxis);
  31.   Serial.print(" Xnorm = ");
  32.   Serial.print(normAccel.XAxis);
  33.   Serial.print(" Ynorm = ");
  34.   Serial.print(normAccel.YAxis);
  35.   Serial.print(" Znorm = ");
  36.   Serial.println(normAccel.ZAxis);
  37.  
  38.   delay(10);
  39. }

Odczyt temperatury

JeÅ›li chodzi odczyt temperatury, realizujemy jÄ… za pomocÄ… funkcji readTemperature().

  1. #include <Wire.h>
  2. #include <MPU6050.h>
  3.  
  4. MPU6050 mpu;
  5.  
  6. void setup()
  7. {
  8.   Serial.begin(115200);
  9.  
  10.   Serial.println("Inicjalizacja MPU6050");
  11.  
  12.   while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  13.   {
  14.     Serial.println("Nie mozna znalezc MPU6050 - sprawdz polaczenie!");
  15.     delay(500);
  16.   }
  17. }
  18.  
  19. void loop()
  20. {
  21.   float temp = mpu.readTemperature();
  22.  
  23.   Serial.print(" Temp = ");
  24.   Serial.print(temp);
  25.   Serial.println(" *C");
  26.  
  27.   delay(500);
  28. }

Filtr Kalmana

UkÅ‚ad MPU6050 z racji posiadania zarówno akcelerometru jak i żyroskopu, pozwala na zastoswanie filtru Kalmana, inaczej mówiÄ…c algorytmu rekurencyjnego. Ponieważ nie jestem wybitnym matematykiem, nie odważę siÄ™ dokÅ‚adnie tÅ‚umaczyć zasady jego dziaÅ‚ania, ale w ogólnym uproszczeniu wykorzystuje on dane żyroskopu do korekcji odczytanych danych z akcelerometru, dziÄ™ki czemu caÅ‚ość dziaÅ‚a wyjÄ…tkowo stabilnie. JeÅ›li masz ochotÄ™, możesz poczytać o nim tutaj: Odczyty Pitch & Roll oraz filtr Kalmana

Detekcja ruchu i bezruchu

MPU6050 pozwala na detekcjÄ™ ruchu i bezruchu caÅ‚ego ukÅ‚adu z wykorzystaniem przerwaÅ„. Na potrzeby tego przykÅ‚adu, nie bÄ™dziemy jednak obsÅ‚ugiwali sprzÄ™towej obsÅ‚ugi przerwania, a jedynie programowej. Zasada dziaÅ‚ania zostaÅ‚a opisana w programie poniżej.

  1. #include <Wire.h>
  2. #include <MPU6050.h>
  3.  
  4. MPU6050 mpu;
  5.  
  6. void setup()
  7. {
  8.   Serial.begin(115200);
  9.  
  10.   Serial.println("Inicjalizacja MPU6050");
  11.  
  12.   while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_16G))
  13.   {
  14.     Serial.println("Nie mozna znalezc MPU6050 - sprawdz polaczenie!");
  15.     delay(500);
  16.   }
  17.  
  18.   // Dodatkowe opoznienie zasilania akcelerometru 3ms
  19.   mpu.setAccelPowerOnDelay(MPU6050_DELAY_3MS);
  20.  
  21.   // Wylaczamy sprzetowe przerwania dla wybranych zdarzen
  22.   mpu.setIntFreeFallEnabled(false);  
  23.   mpu.setIntZeroMotionEnabled(false);
  24.   mpu.setIntMotionEnabled(false);
  25.  
  26.   // Ustawiamy filtr gorno-przepustowy
  27.   mpu.setDHPFMode(MPU6050_DHPF_5HZ);
  28.  
  29.   // Ustawiamy granice wykrywania ruchu na 4mg (zadana wartosc dzielimy przez 2)
  30.   // oraz minimalny czas trwania na 5ms
  31.   mpu.setMotionDetectionThreshold(2);
  32.   mpu.setMotionDetectionDuration(5);
  33.  
  34.   // Ustawiamy granice wykrywania bezruchu na 8mg (zadana wartosc dzielimy przez 2)
  35.   // oraz minimalny czas trwania na 2ms
  36.   mpu.setZeroMotionDetectionThreshold(4);
  37.   mpu.setZeroMotionDetectionDuration(2);    
  38.  
  39.   // Ustawiamy piny 4 i 5 na wyjscia w stanie niskim.
  40.   // Diody podlaczone do tych wyjsc beda sygnalizowaly nasze stany
  41.   pinMode(4, OUTPUT);
  42.   digitalWrite(4, LOW);
  43.  
  44.   pinMode(7, OUTPUT);
  45.   digitalWrite(7, LOW);  
  46. }
  47.  
  48. void loop()
  49. {
  50.   Vector rawAccel = mpu.readRawAccel();
  51.   Activites act = mpu.readActivites();
  52.  
  53.   // Jesli wyrkryto ruch - zapal diode na pinie 4
  54.   if (act.isActivity)
  55.   {
  56.     digitalWrite(4, HIGH);
  57.   } else
  58.   {
  59.     digitalWrite(4, LOW);
  60.   }
  61.  
  62.   // Jesli wyrkryto bezruch - zapal diode na pinie 7
  63.   if (act.isInactivity)
  64.   {
  65.     digitalWrite(7, HIGH);
  66.   } else
  67.   {
  68.     digitalWrite(7, LOW);
  69.   }
  70.  
  71.   delay(50);
  72.  
  73.   digitalWrite(4, LOW);
  74. }

Detekcja upadku swobodnego

Poniższy przykÅ‚ad pokazuje w jaki sposób za pomocÄ… MPU6050 można wykryć upadek swobodny. Tym razem wykorzystamy już przerwanie sprzÄ™towe.

  1. #include <Wire.h>
  2. #include <MPU6050.h>
  3.  
  4. MPU6050 mpu;
  5.  
  6. boolean ledState = false; // aktualny stan diody LED
  7. boolean freefallDetected = false; // czy wykryto upadek swobodny
  8. boolean freefallBlinkCount = 0; // liczba mrugniec diody LED
  9.  
  10. void setup()
  11. {
  12.   Serial.begin(115200);
  13.  
  14.   Serial.println("Inicjalizacja MPU6050");
  15.  
  16.   while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_16G))
  17.   {
  18.     Serial.println("Nie mozna znalezc MPU6050 - sprawdz polaczenie!");
  19.     delay(500);
  20.   }
  21.  
  22.   // Dodatkowe opoznienie zasilania akcelerometru 3ms
  23.   mpu.setAccelPowerOnDelay(MPU6050_DELAY_3MS);
  24.  
  25.   // Wlaczamy obsluge przerwania sprzetowego dla akcji upadku swobodnego 
  26.   mpu.setIntFreeFallEnabled(true);
  27.   mpu.setIntZeroMotionEnabled(false);
  28.   mpu.setIntMotionEnabled(false);
  29.  
  30.   // Ustawiamy filtr gorno-przepustowy
  31.   mpu.setDHPFMode(MPU6050_DHPF_5HZ);
  32.  
  33.   // Aby ruch zostal wykryty jako upadek swobodny, musi wystapic przeciazenie minimum 34mg w czasie 3ms.
  34.   mpu.setFreeFallDetectionThreshold(17);
  35.   mpu.setFreeFallDetectionDuration(2);    
  36.  
  37.   // Dioda podlaczona do pinu 4 bedzie sygnalizowac wykryty stan
  38.   pinMode(4, OUTPUT);
  39.   digitalWrite(4, LOW);
  40.  
  41.   // Aktywujemy obsuge przerwania na pinie 2, aktywne na zbocze narastajace
  42.   attachInterrupt(0, doInt, RISING);
  43. }
  44.  
  45. // Funkcja obslugi przerwania
  46. void doInt()
  47. {
  48.   // resetujemy licznik mrugniec i informujemy program, ze akcja zostala rozponana
  49.   freefallBlinkCount = 0;
  50.   freefallDetected = true;  
  51. }
  52.  
  53. void loop()
  54. {
  55.   Vector rawAccel = mpu.readRawAccel();
  56.   Activites act = mpu.readActivites();
  57.  
  58.   // Jesli wykryto upadek swobodny, dioda LED bedzie mrugac okreslona liczbe razy
  59.   if (freefallDetected)
  60.   {
  61.     ledState = !ledState;
  62.  
  63.     digitalWrite(4, ledState);
  64.  
  65.     freefallBlinkCount++;
  66.  
  67.     if (freefallBlinkCount == 20)
  68.     {
  69.       freefallDetected = false;
  70.       ledState = false;
  71.       digitalWrite(4, ledState);
  72.     }
  73.   }
  74.  
  75.   delay(100);
  76. }

Prezentacja działania

 

Materiały dodatkowe

Biblioteka MPU6050: https://github.com/jarzebski/Arduino-MPU6050

Filtr Kalmana: https://github.com/jarzebski/Arduino-KalmanFilter

MPU6050 rev 3.2: http://www.jarzebski.pl/datasheets/MPU6050_rev32.pdf

MPU6050 rev 3.4: http://www.jarzebski.pl/datasheets/MPU6050_rev34.pdf

MPU6050 rev 4.0: http://www.jarzebski.pl/datasheets/MPU6050_rev40.pdf

MPU6050 rev 4.2: http://www.jarzebski.pl/datasheets/MPU6050_rev42.pdf