Compass with GY-271 and Arduino Nano

This time we're building a digital compass. For this we need one  Arduino nano, on GY-271 module  and one RGB LED ring. We can simply supply the finished device with a 9V battery block.

Circuit:

The circuit is very simple. The GY-271 module and the LED ring are supplied via 5V. So connect GND and connect Vcc to 5V on the Nano. The I2C bus of the GY-271 is connected to the I2C connectors of the Nano. A4 with SDA and A5 with SCL. For the LED ring we connect the signal line to D4 on the nano. For the power supply we connect the negative pole of the battery block to GND and the 9V positive pole via a switch to Vin on the Nano.

The code

Most of the existing libraries are for the HMC5883 which not only has a different I2C address but also a different register assignment. However, since the control of the QMC5883L is very simple, I did not use a library this time.

We can easily use the functions of the Arduino I2C library.

In the case of a soft reset, we set control registers 10 and 11. Interesting is control register 9 with which you can set the important parameters of the QMC5883L.

The operating mode stand-by or continuous measurement. With the output data rate you can determine how many measurements per second should be made. 10 Hz, 50 Hz, 100 Hz or 200 Hz can be selected. The higher this frequency, the higher the power consumption. The sensitivity (rank RNG) indicates the magnetic flux density for full deflection. Here +/- 2 Gauss or +/- 8 Gauss can be selected. With the higher sensitivity, it should be noted that the disruptive influence of external fields increases. Finally, you can set the oversampling rate. 64, 128, 256 and 512 can be set. A higher value reduces the filter bandwidth and thus annoying noise, but this also increases the power consumption.

Those who want to know more details can find them in theQMC5883L datasheet .

The angle to the earth's magnetic field is determined from the read values ​​for x and y. This value is only reasonably accurate if the module is kept as horizontal as possible. For the display, the angle is converted from +/- 180 degrees to 0 to 360 degrees and then divided by 30 so that we get 12 sections corresponding to the 12 LEDs of the ring. The deviation is then used to determine the brightness of the LED. if the deviation is negative, the LED in front and the following LED are also switched on. If the value lies exactly in between, both LEDs light up equally brightly.

For the LED ring we need the NeoPixelBus.h library. The library for the I2C Bus Wire.h is part of the standard installation.

Attention important note:I got an internal compiler error while compiling. Research on the internet showed that this is a problem with the latest Arduino hardware library. Installing the previous version fixed the problem. Simply select version 1.6.22 in the board manager instead of the current 1.6.23 and click Install.

 

 

 

#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

 

For arduinoProjects for beginners

10 comments

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. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN