GY-273 QMC5883L clone HMC5883L magnetometer for Arduino, esp8266 and esp32
A magnetometer is a device that measures magnetic field or magnetic dipole moment. Some magnetometers measure a magnetic field’s direction, strength, or relative change at a particular location.
For example, a compass is a simple magnetometer
With this principle, a device can understand if It’s changed its position or direction on the 3 axis x, y, and z.
I bought this sensor (and others of the same type) for my projects, and found that it is not that simple to use.
First, because many of that isn’t an HMC5883L but a QMC5883L, and the library and address aren’t the same.
Wiring
Here are some simple wiring examples.
esp32:
esp8266, WeMos D1 mini:
Arduino UNO:
Start prototyping
Check variant
The simple way to identify if It’s a QMC5883L variant is to use an i2c scanner. The variant had an address (0x0D) different from the HMC5883L original one.
/*
* i2c scanner
* Renzo Mischianti www.mischianti.org
*/
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
while (!Serial) {delay(100);};
Serial.println();
Serial.println("I2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
delay(5000);
}
if you obtain this output, you have a QMC5883L variant
Scanning...
I2C device found at address 0x0D
done
Scanning...
I2C device found at address 0x0D
done
Library
I use QMC5883LCompass
library that you can find on GitHub, or you can directly download from Arduino Libray manager.
Code
Here is a small code that I wrote, taking parts from some examples and adding the print of the coordinates calculated by the azimuth.
So in the code, first, It asks to calibrate the device and after calibration, start to output the values.
/*
* Simple sketch that use
* QMC5883LCompass.h from https://github.com/mprograms/QMC5883LCompass
* library.
* First the sketch ask to calibrate device so move It, then
* start to output the data
*
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org
*
*/
#include <QMC5883LCompass.h>
QMC5883LCompass compass;
int calibrationData[3][2];
bool changed = false;
bool done = false;
int t = 0;
int c = 0;
bool calibrated = false;
void setup() {
Serial.begin(9600);
// Initialize device with i2c 0x0D address
compass.init();
}
void loop() {
if (!calibrated){
// If not calibrated
int x, y, z;
// Read compass values
compass.read();
// Return XYZ readings
x = compass.getX();
y = compass.getY();
z = compass.getZ();
changed = false;
if(x < calibrationData[0][0]) {
calibrationData[0][0] = x;
changed = true;
}
if(x > calibrationData[0][1]) {
calibrationData[0][1] = x;
changed = true;
}
if(y < calibrationData[1][0]) {
calibrationData[1][0] = y;
changed = true;
}
if(y > calibrationData[1][1]) {
calibrationData[1][1] = y;
changed = true;
}
if(z < calibrationData[2][0]) {
calibrationData[2][0] = z;
changed = true;
}
if(z > calibrationData[2][1]) {
calibrationData[2][1] = z;
changed = true;
}
if (changed && !done) {
Serial.println("CALIBRATING... Keep moving your sensor around.");
c = millis();
}
t = millis();
if ( (t - c > 5000) && !done) {
done = true;
Serial.println("DONE.");
Serial.println();
Serial.print("compass.setCalibration(");
Serial.print(calibrationData[0][0]);
Serial.print(", ");
Serial.print(calibrationData[0][1]);
Serial.print(", ");
Serial.print(calibrationData[1][0]);
Serial.print(", ");
Serial.print(calibrationData[1][1]);
Serial.print(", ");
Serial.print(calibrationData[2][0]);
Serial.print(", ");
Serial.print(calibrationData[2][1]);
Serial.println(");");
compass.setCalibration( calibrationData[0][0], calibrationData[0][1], calibrationData[1][0],
calibrationData[1][1], calibrationData[2][0], calibrationData[2][1]);
calibrated = true;
}
}else{
// If calibrating
int x, y, z;
// Read compass values
compass.read();
// Return XYZ readings
x = compass.getX();
y = compass.getY();
z = compass.getZ();
int azimut = compass.getAzimuth();
float bearing = compass.getBearing(azimut);
Serial.println();
// Write direction
if((azimut < 22.5) || (azimut > 337.5 )) Serial.print("North ");
if((azimut > 22.5) && (azimut < 67.5 )) Serial.print("North-East");
if((azimut > 67.5) && (azimut < 112.5 )) Serial.print("East ");
if((azimut > 112.5) && (azimut < 157.5 )) Serial.print("South-East");
if((azimut > 157.5) && (azimut < 202.5 )) Serial.print("South ");
if((azimut > 202.5) && (azimut < 247.5 )) Serial.print("SOuth-West");
if((azimut > 247.5) && (azimut < 292.5 )) Serial.print("West ");
if((azimut > 292.5) && (azimut < 337.5 )) Serial.print("North-West");
Serial.print(" Azimuth: ");Serial.print(azimut);
Serial.print(" Bearing: ");Serial.print(bearing);
Serial.print(" - X: ");
Serial.print(x);
Serial.print(" Y: ");
Serial.print(y);
Serial.print(" Z: ");
Serial.print(z);
delay(250);
}
}
Here is the serial output result
CALIBRATING... Keep moving your sensor around.
[...]
CALIBRATING... Keep moving your sensor around.
DONE. Copy the line below and paste it into your projects sketch.);
compass.setCalibration(0, 1372, -1106, 0, 0, 966);
North-West Azimuth: 321 Bearing: 14.00 - X: 1130 Y: -948 Z: 492
North-West Azimuth: 320 Bearing: 14.00 - X: 1035 Y: -881 Z: 432
North-West Azimuth: 320 Bearing: 14.00 - X: 941 Y: -814 Z: 374
North-West Azimuth: 319 Bearing: 14.00 - X: 845 Y: -747 Z: 316
North-West Azimuth: 318 Bearing: 14.00 - X: 752 Y: -681 Z: 257
North-West Azimuth: 317 Bearing: 14.00 - X: 656 Y: -614 Z: 197
North-West Azimuth: 316 Bearing: 14.00 - X: 561 Y: -550 Z: 138
North-West Azimuth: 314 Bearing: 13.00 - X: 466 Y: -483 Z: 80
North-West Azimuth: 312 Bearing: 13.00 - X: 372 Y: -417 Z: 22
North-West Azimuth: 312 Bearing: 13.00 - X: 372 Y: -416 Z: 21
North-West Azimuth: 312 Bearing: 13.00 - X: 373 Y: -416 Z: 22
North-West Azimuth: 314 Bearing: 13.00 - X: 383 Y: -399 Z: 24
North-West Azimuth: 319 Bearing: 14.00 - X: 383 Y: -335 Z: 60
North-West Azimuth: 326 Bearing: 14.00 - X: 369 Y: -257 Z: 107
North-West Azimuth: 333 Bearing: 14.00 - X: 348 Y: -179 Z: 165
North Azimuth: 346 Bearing: 15.00 - X: 328 Y: -83 Z: 227
North Azimuth: 4 Bearing: 0.00 - X: 307 Y: 25 Z: 292
North-East Azimuth: 26 Bearing: 1.00 - X: 289 Y: 142 Z: 356
North-East Azimuth: 43 Bearing: 1.00 - X: 272 Y: 260 Z: 420
North-East Azimuth: 55 Bearing: 2.00 - X: 253 Y: 363 Z: 484
North-East Azimuth: 61 Bearing: 2.00 - X: 226 Y: 418 Z: 513
North-East Azimuth: 63 Bearing: 2.00 - X: 223 Y: 447 Z: 515
North-East Azimuth: 63 Bearing: 2.00 - X: 230 Y: 458 Z: 515
North-East Azimuth: 63 Bearing: 2.00 - X: 230 Y: 458 Z: 514
North-East Azimuth: 59 Bearing: 2.00 - X: 247 Y: 425 Z: 496
North-East Azimuth: 53 Bearing: 2.00 - X: 246 Y: 328 Z: 444
North-East Azimuth: 40 Bearing: 1.00 - X: 246 Y: 208 Z: 391
North Azimuth: 18 Bearing: 0.00 - X: 245 Y: 83 Z: 326
North Azimuth: 354 Bearing: 15.00 - X: 259 Y: -31 Z: 264
North-West Azimuth: 332 Bearing: 14.00 - X: 277 Y: -148 Z: 202
North-West Azimuth: 320 Bearing: 14.00 - X: 294 Y: -252 Z: 144
North-West Azimuth: 313 Bearing: 13.00 - X: 312 Y: -338 Z: 99
Good morning,
I would be interested if someone could help me explain how to control the rotation speed of a 24V drive motor and keep its speed constant.
That is, a gyroscope or magnetic sensor would control the speed and it would always be constant.
I can provide my email address if anyone wants to help me.
With ESP32.
If anyone is interested we could discuss more about the system I am setting up. I don’t mind if there is a cost, I am open to a dialogue to specify details.
Thank you very much.
Buenos dias,
Estaría interesado si alguien pudiera ayudarme en explicarme cómo controlar la velocidad e giro de un motor de accionamiento a 24V y que su velocidad sea constante.
Es decir, que un giroscopio o sensor magnético controlara la velocidad y que siempre fuera constante.
Paso mi correo electrónico si alguien quisiera ayudarme.
Con ESP32.
Si hay alguien interesado podríamos hablar más del sistema que estoy montando. No me importa si tiene coste, admito diálogo para concretar.
Muchas gracias.
Hi Severiano,
I think you need a function like this that calculate speed and then control the motor to set a constant speed.
Bye Renzo
Thanks for the code, it is the first compass code that has worked for me !!
I just have an operational question, how should I move the GY-271 during the calibration ?
Does it need to start oriented in a certain way ?
Hi Tommie,
normally I move the device to follow a line of an 8.
Bye Renzo
I have a i2c device that starts with 0x0E address, what changes should I make in my code to make it work with esp32?
Hi,
you must set the address with this command before init
Bye RM