Kompass mit GY-271 und Arduino Nano - AZ-Delivery

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

 

Für arduinoProjekte für anfänger

13 comments

Roland

Roland

Vorsicht mit der I2C-Adresse! Es sind auch Module mit der Adresse 0×1E (ursprüngliche Standardadresse) im Umlauf. Das Datenblatt von Honeywell enthält 0×3C und 0×3D.
Unter https://playground.arduino.cc/Main/I2cScanner/ findet man einen einfachen Adressscanner

Simon

Simon

Hallo, muss das Modul nicht kalibriert werden? Bei mir zeigt er nur 4 LEDs an (Ring getestet) und liefert utopische Werte im Serial Monitor.

LG
Simon

Rüdiger Sachse

Rüdiger Sachse

Ich habe mir den GY-271 besorgt, um mein (Arduino)-Autopilot-Projekt zu verbessern.
Normalerweise ist der AP durchaus in der Lage einen stabilen Kurs zu einem Waypoint zu fahren. Die Navigationsdaten bekommet er von einem GPS-Plotter. Peilung und Crosstrack-Error sind kein Problem, da sich die Werte relativ langsam ändern, aber der aktuelle Kurs und insbesondere die schnelle Kursänderung werden nur verzögert (alle 2-3 Sek) ausgegeben. Das Schiff muss eine gewisse Strecke fahren um den GPS-basierten Kurs zu erhalten. Bei langsamer Fahrt wird die Berechnung immer ungenauer. Mit dem GY-Modul hoffe ich besseren Werte für die schnellen Kursänderungen und damit ein besseres Steuerverhalten zu erzielen.

Hier ist mir etwas merkwürdiges aufgefallen! Die Werte für die X-Y-Z-Achsen werden mit Hilfe der Arduino-Lib Wire.h ausgelesen.
Die Registerinhalte stimmen nicht mit dem Datenblatt überein, Z und Y sind vertauscht!!

code:
Wire.requestFrom(I2C_address, 6); //6 bytes lesen

x = Wire.read()<<8; //X msb //16bit int X-Achse x |= Wire.read(); //X lsb z = Wire.read()<<8; //Z msb //nach datenblatt Y-Achse ?? z |= Wire.read(); //Z lsb y = Wire.read()<<8; //Y msb //nach datenblatt Z-Achse ?? y |= Wire.read(); y+=180; //Y lsb // +180 addieren ??

Die X-Werte liegen symmetrisch zur 0-Linie, bei den Y-Werten muss 180 addiert werden.
Die Z-Werte sind wesentlich höher (bis 900).
Beim Drehen des Moduls um 360 Grad auf dem platten Tisch erhalte ich für X und Y zwei schöne sinusförmige Kurven mit 90 Grad Phasenversatz (COS für X, SIN für Y). Die Minima und Maxima liegen wie zu erwarten bei je 0 (bzw 360), 90, 180 und 270 Grad bezogen auf magnetisch Nord. Die Kurven sind allerdings nicht symmetrisch zur 0-Linie (bei jedem Chip anders), daher muss der Offset-Wert ermittelt werden. Man dreht einen Vollkreis und nimmt die Mitte von Min und Max.

Daraus lässt sich der Radiant, bzw Kompasswinkel mit der Funktion
rad= atan2(y,x) errechnen und bekommt eine tadellose Kompassdarstellung.

Jetzt muss ich nur noch die Einflüsse durch Rollbewegungen kompensieren, aber das ist eine andere Geschichte…

Gerald

Gerald

Hallo Sven offenbar hast Du ein Board mit einem HMC5883. Der Sketch ist für den QMC5883L wie er auf dem Modul von AZ-Delivery verbaut ist. Der HMC5883 hat eine andere I2C Adresse. Folgende Änderung im Sketch ist notwendig damit der HMC5883 funktioniert.
//I2C address of the QMC5883L
#define ADDR 0×17
Dann sollte es funktionieren.

sven

sven

ich habe das problem,
X Value: -1
Y Value: -1
Z Value: -1
Richtung: 135.00°
LED 1 = 11 bright = 15
LED 2 = 10 bright = 15
es zeigt immer die selben werte an.

Beim arduino example HMC5883L geht es.

Ulrich Engel

Ulrich Engel

Hallo Gerald,
nun funktioniert der Kompass wie gewünscht. Es waren aber Änderungen notwendig.
Erst einmal habe ich, auf Anraten eines “Profis”, das GY-271 Modul etwas (8-10 cm) vom Ring und dem Nano entfernt, um Magnetfeldeinflüsse durch Strom zu verhindern. Dann habe ich das Modul untersucht und festgestellt, dass es sich nicht um einen “original/generic” Chip handelt. Man erkennt dieses Original am Aufdruck auf dem kleinen schwarzen Chip auf dem Modul. Beim Original steht “L5883 2120”. Beim Fake, der nicht funktioniert steht “DA 5883 8012”.

Ulrich Engel

Ulrich Engel

Hallo Gerald,
vielen Dank für die Antwort. Ich habe noch einmal gemäß Deiner Beschreibung die Verdrahtung kontrolliert. Dann habe ich den Kompass von Google Maps auf dem Handy eingeschaltet. Der zeigt stabil nach N wenn ich das Handy auf dem Tisch flach drehe.
Eigentlich hatte ich dieses auch für die LEDs im Ring erwartet. Es sollten doch die leuchtenden LEDs (2 Stück) beim flachen Drehen der Schaltung (x-Y des Sensors) immer in die gleiche Richtung zeigen. Nämlich nach N.
Das ist bei mir leider nicht der Fall. Es bleiben immer die gleichen LEDs an und drehen mit.
Ich habe noch kein Projekt mit einem Nano gemacht. Ist es normal, dass der schwarze Chip sehr heiß wird?

Viele Grüße aus Berlin
Ulli

Gerald

Gerald

Hallo Ulrich
Ich habe jetzt die Schaltung nochmals aufgebaut. Beim Erdmagnetfeld sollten die Werte für X und Y in einem Bereich von +/- 2000 liegen und für Z bei -3000 bis -5000. Dein Y Wert ist ziemlich konstant bei etwa -6000. Ich vermute daher, dass ein externes Magnetfeld in Y Richtung vorhanden ist, das den Einfluß des Erdmagnetfeldes überdeckt. Du solltest mal die Schaltung mit Batterie betreiben und möglichst von Störquellen (Elektrogeräte) entfernt testen.

Ulrich Engel

Ulrich Engel

Hallo Gerald,
eigentlich hatte ich erhofft, dass ich Euren Erfahrungsschatz nutzen kann und Unterstützung bei meinem Problem erhalte. Ich würde gerne das Projekt fertig bekommen und bei meinem Geo-Cacher (Projekt von Euch) nutzen.
Viele Grüße
Ulli aus Berlin

Ulrich Engel

Ulrich Engel

Hallo,
super Idee. Tolle Ergänzung zum Tutorial “Geocaching”.
Kompilieren und Hochladen (wenn man auf Old Bootloader umschaltet) funktioniert fehlerfrei.
Mein Problem ist leider, dass die Daten, die auf den serial monitor ausgegeben werden sehr wir sind. Auch bleiben die LEDs immer an der gleichen Stelle an, wenn ich den ganzenAufbau drehe.
Hier ein Auszug. Wo könnte ich den die Ergebnisliste als Datei posten?
Start
init done
X Value: 0Y Value: 0Z Value: 0Richtung:
0.00°LED 1 = 5 bright = 0LED 2 = 6 bright = 30

X Value: -1187Y Value: -8795Z Value: -6610Richtung:
97.69°LED 1 = 10 bright = 7LED 2 = 9 bright = 23

X Value: -1177Y Value: -8857Z Value: -6552Richtung:
97.57°LED 1 = 10 bright = 7LED 2 = 9 bright = 23

X Value: -1245Y Value: -8765Z Value: -6572Richtung:
98.08°LED 1 = 10 bright = 8LED 2 = 9 bright = 22

X Value: -1270Y Value: -6092Z Value: -6647Richtung:
101.78°LED 1 = 10 bright = 11LED 2 = 9 bright = 19

X Value: -1265Y Value: -5975Z Value: -6615Richtung:
101.95°LED 1 = 10 bright = 11LED 2 = 9 bright = 19

X Value: -1335Y Value: -5960Z Value: -6662Richtung:
102.63°LED 1 = 10 bright = 12LED 2 = 9 bright = 18

X Value: -1317Y Value: -5950Z Value: -6657Richtung:
102.48°LED 1 = 10 bright = 12LED 2 = 9 bright = 18

X Value: -1355Y Value: -6017Z Value: -6720Richtung:
102.69°LED 1 = 10 bright = 12LED 2 = 9 bright = 18

X Value: -1302Y Value: -6042Z Value: -6630Richtung:
102.16°LED 1 = 10 bright = 12LED 2 = 9 bright = 18

X Value: -4462Y Value: -6542Z Value: -6672Richtung:
124.30°LED 1 = 11 bright = 4LED 2 = 10 bright = 26

X Value: -4375Y Value: -6430Z Value: -6657Richtung:
124.23°LED 1 = 11 bright = 4LED 2 = 10 bright = 26

X Value: -4197Y Value: -6415Z Value: -6695Richtung:
123.19°LED 1 = 11 bright = 3LED 2 = 10 bright = 27

X Value: -4232Y Value: -6390Z Value: -6705Richtung:
123.52°LED 1 = 11 bright = 3LED 2 = 10 bright = 27

X Value: -4232Y Value: -6425Z Value: -6732Richtung:
123.37°LED 1 = 11 bright = 3LED 2 = 10 bright = 27

Könnte dieses an dem Sensor liegen? Wie ich gelesen habe, werden ja oft auch unter gleichem Namen auch Nicht-Originale angeboten, die man nur am Aufdruck auf dem Chip identifizieren kann.
Ich habe wohl so einen “Fake” erwischt.

Wolfgang

Wolfgang

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

Gerald

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

Wolfgang Butenhoff

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”.

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery