Magnetometer HMC5883L Interfacing with NodeMCU
Introduction
Magnetometer HMC5883L Module
HMC5883L is a 3-axis magnetometer which is used for measuring the direction and magnitude of the Earth’s magnetic field. It is used for low cost compassing and magnetometry.
It measures the Earth’s magnetic field value along the X, Y and Z axes from milli-gauss to 8 gauss.
It can be used to find the direction of heading of the device.
It uses I2C protocol for communication with the microcontroller.
For more information about Magnetometer HMC5883L and how to use it, refer the topic HMC5883L Magnetometer Module in the sensors and modules section.
A NodeMCU can communicate with this module using I2C communication protocol. To know more about I2C functions in NodeMCU refer NodeMCU I2C with ESPlorer IDE or NodeMCU I2C with Arduino IDE
Interfacing Diagram
Interfacing HMC5883L Module with NodeMCU
Example
Reading x, y, z axis from the HMC5883L magnetometer module, calculate heading angle from these three axes and displaying heading angle on Serial Monitor.
First, do the connections as shown in above interfacing diagram.
Now let’s write program NodeMCU for reading values from HMC5883L magnetometer.
We can write codes for NodeMCU DevKit in either Lua Script or C/C++ language. We are using ESPlorer IDE for writing code in Lua scripts and Arduino IDE for writing code in C/C++. To know more refer Getting started with NodeMCU using ESPlorer IDE (which uses Lua scripting for NodeMCU) and Getting started with NodeMCU using Arduino IDE (which uses C/C++ language based Arduino sketches for NodeMCU).
NodeMCU functions for HMC5883L
Below are functions that are used for HMC5883L module in NodeMCU firmware. We need to add this module while building NodeMCU firmware to avail its function for use.
hmc5883l.init()
This function Initializes the HMC5883L module and sets the pin configuration.
Note: as per NodeMCU doc says that “
hmc5883l.init()
function is deprecated and will be removed in upcoming releases. Use hmc5883l.setup()
instead”. But while testing hmc5883l.init()
is working and hmc5883l.setup()
not. So be sure about which function for initialize.
Syntax:
hmc5883l.init(sda, scl)
Parameters:
sda
: serial data pin of i2c interface.scl
: serial clock pin of i2c interface.
Returns: Nil
hmc5883l.setup()
This function initializes the module.
Syntax:
hmc5883l.setup()
Parameters: None
Returns: nil
Example:
local sda, scl = 1, 2
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
hmc5883l.setup()
hmc5883l.read()
This function samples the sensor and returns X, Y and Z axis data.
Syntax:
hmc5883l.read()
Returns: x,y,z measurements (integers) temperature multiplied with 10 (integer)
Example:
local sda, scl = 1, 2
hmc5883l.init(sda, scl)
local x, z ,y = hmc5883l.read()
print(string.format("x = %d, y = %d, z = %d", x, y, z))
let’s write lua script to read x, y, z from HMC5883l and calculate heading angle from it
Lua Script for NodeMCU
id = 0 -- always 0
scl = 5 -- set pin 6 as scl
sda = 6 -- set pin 7 as sda
--Define declination of location from where measurement going to be done.
--e.g. here we have added declination from location Pune city, India.
--we can get it from http://www.magnetic-declination.com
pi = 3.14159265358979323846
Declination = -0.00669
function arcsin(value)
local val = value
local sum = value
if(value == nil) then
return 0
end
-- as per equation it needs infinite iterations to reach upto 100% accuracy
-- but due to technical limitations we are using
-- only 10000 iterations to acquire reliable accuracy
for i = 1, 10000, 2 do
val = (val*(value*value)*(i*i)) / ((i+1)*(i+2))
sum = sum + val;
end
return sum
end
function arctan(value)
if(value == nil) then
return 0
end
local _value = value/math.sqrt((value*value)+1)
return arcsin(_value)
end
function atan2(y, x)
if(x == nil or y == nil) then
return 0
end
if(x > 0) then
return arctan(y/x)
end
if(x < 0 and 0 <= y) then
return arctan(y/x) + pi
end
if(x < 0 and y < 0) then
return arctan(y/x) - pi
end
if(x == 0 and y > 0) then
return pi/2
end
if(x == 0 and y < 0) then
return -pi/2
end
if(x == 0 and y == 0) then
return 0
end
return 0
end
hmc5883l.init(sda, scl) --initialize hmc5883l
while true do --read and print accelero, gyro and temperature value
local x,z,y = hmc5883l.read()
Heading = atan2(y, x) + Declination
if (Heading>2*pi) then --Due to declination check for >360 degree
Heading = Heading - 2*pi
end
if (Heading<0) then --Check for sign
Heading = Heading + 2*pi
end
Heading = Heading*180/pi --convert radian to angle
print(string.format("Heading angle : %d", Heading))
tmr.delay(10000) -- 10ms timer delay
end
ESPlorer Serial Output Window
Output window of ESPlorer IDE serial window for above lua script is shown below
Now let’s write same example in Arduino ide for NodeMCU
Arduino Sketch for NodeMCU
#include <Wire.h>
/* Define declination of location from where measurement going to be done.
e.g. here we have added declination from location Pune city, India.
we can get it from http://www.magnetic-declination.com */
#define Declination -0.00669
#define hmc5883l_address 0x1E
void setup() {
Serial.begin(9600); /* begin serial for debug */
Wire.begin(D6, D5); /* join i2c bus with SDA=D6 and SCL=D5 of NodeMCU */
hmc5883l_init();
}
void loop() {
Serial.print("Heading Angle : ");
Serial.println(hmc5883l_GetHeading());
delay(150);
}
void hmc5883l_init(){ /* Magneto initialize function */
Wire.beginTransmission(hmc5883l_address);
Wire.write(0x00);
Wire.write(0x70); //8 samples per measurement, 15Hz data output rate, Normal measurement
Wire.write(0xA0); //
Wire.write(0x00); //Continuous measurement mode
Wire.endTransmission();
delay(500);
}
int hmc5883l_GetHeading(){
int16_t x, y, z;
double Heading;
Wire.beginTransmission(hmc5883l_address);
Wire.write(0x03);
Wire.endTransmission();
/* Read 16 bit x,y,z value (2's complement form) */
Wire.requestFrom(hmc5883l_address, 6);
x = (((int16_t)Wire.read()<<8) | (int16_t)Wire.read());
z = (((int16_t)Wire.read()<<8) | (int16_t)Wire.read());
y = (((int16_t)Wire.read()<<8) | (int16_t)Wire.read());
Heading = atan2((double)y, (double)x) + Declination;
if (Heading>2*PI) /* Due to declination check for >360 degree */
Heading = Heading - 2*PI;
if (Heading<0) /* Check for sign */
Heading = Heading + 2*PI;
return (Heading* 180 / PI);/* Convert into angle and return */
}
/* Uncomment below function for reading status register */
//uint8_t readStatus(){
// Wire.beginTransmission(hmc5883l_address);
// Wire.write(0x09);
// Wire.endTransmission();
// Wire.requestFrom(hmc5883l_address, 1);
// return (uint8_t) Wire.read();
//}
Arduino Serial Output Window
Output window of Arduino IDE serial window for above Arduino sketch is shown below
Note that heading also gets affected by device tilt and nearby magnetic devices effect. There are compensating methods provided in the attached document.
Supporting Files
Source Code
- NodeMCU HMC5883L Source files Download 183
Attached File
- Applications of Magnetic Sensors for Low Cost Compass Systems Download 268
- Applications of Magneto-resistive Sensors in Navigation Systems Download 260
- HMC5883L 3-Axis Digital Compass IC Datasheet Download 281
No comments:
Post a Comment