LinkedIn YouTube Facebook
Szukaj

Wstecz
SoM / SBC

[PRZYKŁAD] Akcelerometr i magnetometr KAmodLSM303 + Arduino

Mając przygotowany i połączony sprzęt możemy można przejść do oprogramowania Arduino (pełny kod źródłowy znajduje się w sekcji „Do pobrania”). W pierwszym kroku dołączamy biblioteki sterujące wyświetlaczem LCD oraz czujnikiem LSM303. Następnie deklarujemy wszystkie niezbędne zmienne oraz funkcje. Krótkie omówienie ich roli znajduje się w komentarzach do kodu.

#include <LiquidCrystal.h>
#include <Wire.h>
#include "LSM303.h"
LSM303 akcelerometr;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);    
float acc_x, acc_y, acc_z, mag_x, mag_y, mag_z, kat; //zmienne w których przechowywane będą wyskalowane odczyty czujnika
float ax_offset = 0, ay_offset = 0, az_offset = 0;   //zmienne kalibrujące odczyty akcelerometru
void wyswieltPrzyspieszenie(void);                   //deklaracja funkcji odczytującej i wyświetlającej wskazania akcelerometru
void wyswietlKompas(void);                           //deklaracja funkcji odczytującej i wyświetlającej wskazania kompasu
void wyswietlMagnetometr (void);                     //deklaracja funkcji odczytującej i wyświetlającej wskazania magnetometru
void (*wskaznikFunkcji) (void);                      //wskaźnik na funkcję która ma zostać wykonana w danej iteracji pętli
void (*tablicaFunkcji[3])(void) = {wyswieltPrzyspieszenie, wyswietlMagnetometr, wyswietlKompas};   //tablica wskaźników do funkcji odczytujacych i wyswietlajacych dane
unsigned short int f=0;                              //numer aktualnie używanej funkcji
int stat;                                            //odczyt z linii A0, podłączonej do klawiatury

Funkcja klawiatura() umożliwia odczyt stanów przycisków na nakładce. Warto zauważyć, że wszystkie przyciski są połączone z jedną linią analogową mikrokontrolera. W związku z tym napięcie na tej linii informuje nas o tym, który przycisk został naciśnięty. Zalecane wartości dla poszczególnych przycisków zostały podane m.in. w przykładzie producenta. W naszym przykładzie, przyciski UP i DOWN zmieniają rodzaj wyświetlanych wartości, zaś przyciskiem SELECT włączamy procedurę kalibracji odczytów akcelerometru. Wartości wskazujące na naciśnięcie któregoś z tych przycisków limitowane są zarówno od góry, jak i od dołu tak, aby przyciski nieużywane w przykładzie (tj. LEFT i RIGHT) nie powodowały żadnej reakcji przyrządu. Obsługa zmiany wyświetlanych wartości polega na odwoływaniu się do bufora kołowego wskaźników do funkcji. W przypadku naciśnięcia przycisku UP do wskaźnika wskaznikFunkcji wpisywany jest wskaźnik na następną funkcję, w przypadku naciśnięcia przycisku DOWN – na poprzednią. W funkcji loop() aktualna funkcja wywoływana jest już przez wskaźnik. Takie rozwiązanie pozwala na szybkie i niezawodne przejście przez procedurę wyboru aktualnie wyświetlanej funkcji, zwłaszcza dla przypadku, gdy żaden przycisk nie jest wciśnięty.

void klawiatura (void) //Odczyt klawiatury i wybór funkcji
{
  stat = analogRead(A0);

  if (stat > 1000) return; 

  if (stat < 250 && stat > 50)     // naciśnięcie przycisku UP
  {
    wskaznikFunkcji = tablicaFunkcji[(++f)%=3];
    delay(100);
    return;
  }
  if (stat < 450 && stat > 250 )   // naciśnięcie przycisku DOWN
  {
    wskaznikFunkcji = tablicaFunkcji[f=(f+2)%3];
    delay(100);
    return;
  }
  if (stat < 850 && stat > 650)    //naciśnięcie przycisku SELECT
  {
    kalibracja();
    return; 
  }
}

W funkcji kalibracja() odbywa się kalibracja odczytów akcelerometru. Funkcja jest wywoływana raz na początku każdego użycia przyrządu. Można ją wywołać w każdej chwili przez naciśnięcie przycisku SELECT. Funkcja wypisuje na wyświetlaczu komunikat o ustawieniu w pozycji płaskiej. Pozycja płaska to taka pozycja, gdy płytka jest równolegle do ziemi, a czujnik znajduje się na górnej powierzchni płytki. Wtedy oś Z akcelerometru skierowana jest pionowo do ziemi. Tak ułożony jest czujnik na zdjęciu ukazującym podłączenie przyrządów. Funkcja informuje o rozpoczęciu procedury kalibracji, a także o jej zakończeniu. Wartości offset wyznaczone w tej procedurze pozwalają na dokładniejszy odczyt z akcelerometru.

void kalibracja(void) //kalibracja akcelerometru
{
  const int liczbaProbek = 1024;
  acc_x=0;
  acc_y=0;
  acc_z=0;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.println("Ustaw czujnik w ");
  lcd.setCursor(0,1);
  lcd.println("pozycji plaskiej");
  delay(5000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.println("Kalibracja       ");
  for (int i=0; i<=liczbaProbek; ++i)
  {
    akcelerometr.read();
    acc_x+=(2.0/32768.0)*akcelerometr.a.x;
    acc_y+=(2.0/32768.0)*akcelerometr.a.y;
    acc_z+=(2.0/32768.0)*akcelerometr.a.z;
  }
  ax_offset = acc_x / liczbaProbek;
  ay_offset = acc_y / liczbaProbek;
  az_offset = (acc_z / liczbaProbek)-1;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.println("Kalibracja      ");
  lcd.setCursor(0,1);
  lcd.println("Zakonczona      ");
  delay(1500); 
  return;
}

Funkcja wyswietlPrzyspieszenie() odczytuje oraz wyświetla na ekranie wskazania akcelerometru w trzech kierunkach: X, Y i Z. Wyświetlane wartości są skalowane w zakresie ±2G (dwukrotność przyspieszenia ziemskiego), który jest domyślnie ustawiany w bibliotece. Wartości przyspieszenia są ułożone na ekranie w sposób intuicyjny: na górze od lewej X i Y, na dole od lewej Z i napis przypominający jakie wartości są obserwowane.

void wyswietlPrzyspieszenie(void) //definicja funkcji odczytującej i wyświetlającej wskazania akcelerometru
{
  akcelerometr.readAcc();
  acc_x=((2.0/32768.0)*akcelerometr.a.x)-ax_offset;
  acc_y=((2.0/32768.0)*akcelerometr.a.y)-ay_offset;
  acc_z=((2.0/32768.0)*akcelerometr.a.z)-az_offset;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(acc_x);
  lcd.print(" G");
  lcd.setCursor(8,0);
  lcd.print(acc_y);
  lcd.print(" G");
  lcd.setCursor(0,1);
  lcd.print(acc_z);
  lcd.print(" G");
  lcd.setCursor(10,1);
  lcd.print("ACC");
  delay(100);
}

Funkcja wyswietlMagnetometr() działa podobnie jak funkcja poprzednia z tą różnicą, że wyświetla wskazania magnetometru. Warto zauważyć, że wskazania magnetometru nie są w tym przyrządzie kalibrowane. Domyślnym zakresem pomiarowym przy korzystaniu z biblioteki Pololu jest ±4 Gausy i do tej wartości skalowane są wyniki.

void wyswietlMagnetometr(void)  //definicja funkcji odczytującej i wyświatlającej wskazania magnetometru
{
  akcelerometr.readMag(); 
  mag_x=(4.0/32768.0)*akcelerometr.m.x;
  mag_y=(4.0/32768.0)*akcelerometr.m.y;
  mag_z=(4.0/32768.0)*akcelerometr.m.z;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(mag_x);
  lcd.setCursor(8,0);
  lcd.print(mag_y);
  lcd.setCursor(0,1);
  lcd.print(mag_z);
  lcd.setCursor(10,1);
  lcd.print("MAG");
  delay(100);
}

Funkcja wyswietlKompas() wyświetla odchylenie wektora X od bieguna N w stopniach, czyli działa jak prosty kompas. Wykorzystywana jest tu funkcja biblioteczna heading(). Kompas najlepiej sprawuje się, gdy leży równolegle do ziemi. Wszelkie odchylenia od tej pozycji znacznie zakłamują jego odczyt.

void wyswietlKompas(void) //definicja funkcji odczytującej i wyświatlającej wskazania kompasu
{
    akcelerometr.read();
    acc_x = akcelerometr.heading();

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("WYCHYLENIE");
    lcd.setCursor(0,1);
    lcd.print(acc_x);
    lcd.print(" st.");
    delay(100);
}

W funkcji setup() inicjalizowane są: ekran LCD, czujnik LSM303 oraz transmisja I2C. Wywoływana jest także procedura kalibracja(), aby skalibrować odczyty akcelerometru jeszcze przed jakimikolwiek pomiarami.

void setup()
{
  Wire.begin(); //inicjalizacja połączenia I2C
  lcd.begin(16,2); //inicjalizacja ekranu       
  lcd.setCursor(0,0);
  akcelerometr.init(); //inicjalizacja czujnika
  akcelerometr.enableDefault();
  kalibracja(); //wywołanie procedury kalibracyjnej
  wskaznikFunkcji = tablicaFunkcji[f];
}

W funkcji loop() wywoływana jest procedura obsługi klawiatury, a następnie przez wskaźnik funkcja wyświetlająca odczyty zgodnie z aktualnymi potrzebami.

void loop()
{
  klawiatura();
  wskaznikFunkcji();
}

Działanie projektu przedstawione jest na poniższym filmie: