Kompass mit GY-271 und Arduino Nano

Diesmal bauen wir einen digitalen Kompass. Dazu benötigen wir einen Arduino-Nano, ein GY-271 Modul und einen RGB-LED-Ring. Das fertige Gerät können wir einfach über einen 9V Batterieblock versorgen.

Schaltung:

Die Schaltung ist sehr einfach. Das GY-271 Modul und der LED-Ring werden über 5V versorgt. Also GND verbinden und Vcc mit 5V am Nano verbinden. Der I2C Bus des GY-271 wird mit den I2C Anschlüssen des Nano verbunden. Und zwar A4 mit SDA und A5 mit SCL. Für den LED-Ring verbinden wir die Signalleitung mit D4 am Nano. Für die Stromversorgung verbinden wir den Minuspol des Batterieblocks mit GND und den 9V Pluspol über einen Schalter mit Vin am Nano.

 Der Code

Die meisten der vorhandenen Bibliotheken sind für den HMC5883 der nicht nur eine unterschiedliche I2C Adresse sondern auch eine unterschiedliche Registerbelegung hat. Da aber die Ansteuerung des QMC5883L sehr einfach ist habe ich diesmal auf den Einsatz einer Bibliothek verzichtet. 

Wir können ganz einfach die Funktionen der Arduino I2C Bibliothek verwenden.

Beim  Soft-Reset setzen wir die Steuer-Register 10 und 11. Interessant ist das Steuerregister 9 mit dem man die wichtigen Parameter des QMC5883L einstellen kann.

Die Betriebsart Stand-By oder andauernde Messung. Mit der Ausgangs Datenrate kann man festlegen wie viele Messungen pro Sekunde gemacht werden sollen. 10 Hz, 50 Hz, 100 Hz oder 200 Hz können gewählt werden. Je höher diese Frequenz desto höher ist der Stromverbrauch. Die Empfindlichkeit (Rang RNG) gibt die magnetische Flussdichte für Vollausschlag an. Hier kann +/- 2 Gauss oder +/- 8 Gauss gewählt werden. Bei der höheren Empfindlichkeit ist zu beachten, dass der störende Einfluss von Fremdfeldern zunimmt. Zuletzt kann man noch die Oversampling Rate einstellen. Es ist 64, 128, 256 und 512 einstellbar. Ein höherer Wert reduziert die Filter-Bandbreite und damit störendes Rauschen, allerdings nimm auch dadurch der Stromverbrauch zu.

Wer noch mehr Details wissen will findet diese im Datenblatt zum QMC5883L .

Aus den gelesen Werten für x und y wird der Winkel zum Erdmagnetfeld bestimmt. Dieser Wert ist nur dann halbwegs genau wenn das Modul möglichst waagerecht gehalten wird. Zur Darstellung wird der Winkel von +/- 180 Grad auf 0 bis 360 Grad umgerechnet und dann durch 30 dividiert sodass wir 12 Abschnitte entsprechend zu den 12 LEDs des Rings erhalten. Die Abweichung wird dann dazu herangezogen die Helligkeit der LED zu bestimmen. ist die Abweichung negativ wird auch noch die davorliegende LED und sonst die folgende LED eingeschaltet. Liegt der Wert genau dazwischen leuchten beide LEDs gleich hell.

Für den LED Ring brauchen wir die NeoPixelBus.h Bibliothek. Die Bibliothek für den I2C Bus Wire.h gehört zur Standardinstallation.

Achtung wichtiger Hinweis: Ich habe beim Kompilieren einen internen Kompilerfehler erhalten. Recherchen im Internet ergaben, dass dies ein Problem mit der neuesten Arduino-Hardware Bibliothek ist. Eine Installation der vorherigen Version, beseitigte das Problem. Im Boardverwalter einfach die Version 1.6.22 statt der aktuellen 1.6.23 wählen und Installieren klicken.

 

 

 

#include <Wire.h> //I2C Arduino Library
#include <NeoPixelBus.h> //library for led strip

//I2C address of the QMC5883L
#define ADDR  0x0d

//values for the QMC5883 control register 1
//operating mode
#define Mode_Standby    0b00000000
#define Mode_Continuous 0b00000001
//Output data rate
#define ODR_10Hz        0b00000000
#define ODR_50Hz        0b00000100
#define ODR_100Hz       0b00001000
#define ODR_200Hz       0b00001100
//Measure range
#define RNG_2G          0b00000000
#define RNG_8G          0b00010000
//Over sampling rate
#define OSR_512         0b00000000
#define OSR_256         0b01000000
#define OSR_128         0b10000000
#define OSR_64          0b11000000

//some constants for the LED ring
#define MAXBRIGHT 64
#define LEDCOUNT 12
#define SIGNALPIN 4

//initialize LED strip driver
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(LEDCOUNT, SIGNALPIN);

//define color black to switch leds off
RgbColor black(0,0,0);

//function to write data into a register on QMC5883L
void writeRegister(uint8_t reg, uint8_t val){
  Wire.beginTransmission(ADDR); //start talking
  Wire.write(reg); 
  Wire.write(val);
  Wire.endTransmission();
}

//function to read results from QMC5883L
void readData(uint16_t * x, uint16_t * y, uint16_t * z) {
  Wire.beginTransmission(ADDR);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(ADDR, 6);
  *x = Wire.read(); //LSB  x
  *x |= Wire.read() << 8; //MSB  x
  *y = Wire.read(); //LSB  z
  *y |= Wire.read() << 8; //MSB z
  *z = Wire.read(); //LSB y
  *z |= Wire.read() << 8; //MSB y  
}

//function to set the control register 1 on QMC5883L
void setCtrlRegister(uint8_t overSampling, uint8_t range, uint8_t dataRate, uint8_t mode) {
  writeRegister(9,overSampling | range | dataRate | mode);
}

//function to reset QMC5883L
void softReset() {
  writeRegister(0x0a,0x80);
  writeRegister(0x0b,0x01);
}

//prepare hardware
void setup(){
  Serial.begin(9600);
  Wire.begin();
  
  Serial.println("Start");
  softReset();
  setCtrlRegister(OSR_128,RNG_2G,ODR_100Hz,Mode_Continuous);
  Serial.println("init done");
}


void loop(){
  int x,y,z; //triple axis data
  float azimut;
  uint16_t azi; //azimut only positiv as integer
  uint8_t led1,led2;
  uint8_t val1,val2;
  int8_t diff;
  
  // this resets all the neopixels to an off state
  strip.Begin();
  strip.Show();

  readData(&x, &y, &z); //read data from sensor
  //calculate the angle between x and y
  //wechange the signe since leds in the ring ordered clockwise   
  azimut = -atan2(y,x) * 180.0/PI;
  //add 180 degree to get only positive values
  azi = azimut+180;
  //we have 12 leds every 30 degrees
  led1=(azi/30) % 12;
  //we calculate the difference between original angle
  //and led angle gives at maximum +/- 30
  diff = azi - led1 *30;
  //we want to show both leds left and right to the
  //original angle
  if (diff>0) {
    //if difference is positiv we set the following led
    led2 = led1++;
    if (led2 > 11) led2 = 0;
    val1 = diff;
    val2 = 30-diff; 
  } else {
    //if difference is negative we set the previous led
    led2 = led1--;
    if (led2<0) led2 = 11;
    val1 = -diff;
    val2 = 30+diff;
  }
  //switch all leds off
  strip.ClearTo(black);
  //set the wo leds on the calculated value with red
  RgbColor col1(val1*MAXBRIGHT/30,0,0);
  strip.SetPixelColor(led1,col1);
  RgbColor col2(val2*MAXBRIGHT/30,0,0);
  strip.SetPixelColor(led2,col2);
  //send data to the led ring
  strip.Show();
  // Show values on serial line
  Serial.print("X Value: ");
  Serial.println(x);
  Serial.print("Y Value: ");
  Serial.println(y);
  Serial.print("Z Value: ");
  Serial.println(z);
  Serial.print("Richtung: ");
  Serial.print(azimut);
  Serial.println("°");
  Serial.print("LED 1 = ");
  Serial.print(led1);
  Serial.print(" bright = ");
  Serial.println(val1);
  Serial.print("LED 2 = ");
  Serial.print(led2);
  Serial.print(" bright = ");
  Serial.println(val2);
  Serial.println();
  //wait 1 second
  delay(1000);
}


 

Viel Spass mit dem Kompass

Gerald

 

Letzter Artikel WPS mit dem ESP8266

Kommentar

Wolfgang - April 17, 2019

Danke Gerald,
ich habe die Fehler gefunden.
Das Hochladen des Programmes ohne zusätzliches Modul hat es dann gebracht.
Frohe Ostern an alle
Wolfgang

Gerald - April 14, 2019

Hallo Wolfgang, die Fehlermeldung “stray 302” bedeutet dass ein Sonderzeichen im code vorkommt. Es gibt dazu einen sehr ausführlichen Blog Beitrag, der zeigt wie man diesen Fehler finden und beheben kann. Suche einfach nach “kodierungsfehler-schnell-beheben”.
Im Bereich Posts findest Du dann den Link.

Wolfgang Butenhoff - April 14, 2019

Hallo,
bei der Programmzeile:
setCtrlRegister(OSR_128,RNG_2G,ODR_100Hz,Mode_Continuous);
bekomme ich immer wieder die Meldung: " stray’ \302’ in program"
Wo ist der Fehler? Der Hinweis mit Version 1.6.22 ist berücksichtigt.
Für die Software brauche ich Hilfe ….die Hardware ist bestimmt richtig “verdrahtet”.

Hinterlasse einen Kommentar

Kommentare müssen vor der Veröffentlichung überprüft werden

Erforderliche Angabe