Hi Zim,
I received the QMC5883L module and I played a little bit with it.
First of all I tried to use it directly in basic, without any library and, finally, I must say that it works not so bad.
You can find below a little sketch with my experimental code; basically the sensor must be calibrated trying to find the offset and the scale on each axis (mainly the X and Y for the heading purposes).
The code below simply do a "calibration" for a given time (In the example there are 200 iterations for the calibration = ~20 seconds).
The calibration consists into rotating the sensor slowly all around the horizontal plane; the program will take the min / max for each axis and will compute the required offset / scale.
After that the sensor will give the correct output in degrees.
Take care that the sensor is very sensitive to magnetic fields, ferromagnetic elements or electronic devices in proximity.
Try and let me know if it works for you and, eventually, I'll integrate this code inside Annex.
Code: [Local Link Removed for Guests]
I2C.SETUP 21, 22
address = &H0D ' Address of the device QMC5883
ioBuff.dim(0, 6) ' To save the measurement result
i2c.writeRegByte address, &H0A, &B10000000 ' SOFT_RST
pause 100
i2c.writeRegByte address, &H0B, 1 ' start
pause 100
'i2c.writeRegByte address, &H09, &B00000001 ' 512 samples, 2 gauss, 10Hz, continuous
i2c.writeRegByte address, &H09, &B00010001 ' 512 samples, 8 gauss, 10Hz, continuous
xmin = 1e10: xmax = -1e10
ymin = 1e10: ymax = -1e10
zmin = 1e10: zmax = -1e10
calib = 0
CYCLES_TO_CALIB = 200
while 1
i2c.read_ioBuff(0), address, &H00, 6
x = ioBuff.read(0, 0) OR (ioBuff.read(0, 1) << 8)
if x > 32768 then x = x - 65536
y = ioBuff.read(0, 2) OR (ioBuff.read(0, 3) << 8)
if y > 32768 then y = y - 65536
z = ioBuff.read(0, 4) OR (ioBuff.read(0, 5) << 8)
if z > 32768 then z = z - 65536
'wlog "x="; x, "y="; y, "z=";z
'wlog "xmin="; xmin, "xmax="; xmax, "ymin="; ymin, "ymax="; ymax
if ((calib> 5) and (calib< CYCLES_TO_CALIB)) then
if (x < xmin) xmin = x
if (x > xmax) xmax = x+0.1
if (y < ymin) ymin = y
if (y > ymax) ymax = y+0.1
if (z < zmin) zmin = z
if (z > zmax) zmax = z+0.1
endif
xoff = (xmax+xmin) / 2
yoff = (ymax+ymin) / 2
zoff = (zmax+zmin) / 2
xdelta = (xmax-xmin)
ydelta = (ymax-ymin)
zdelta = (zmax-zmin)
xscale = 1/xdelta
yscale = 1/ydelta
zscale = 1/zdelta
x = (x-xoff) * xscale
y = (y-yoff) * yscale
z = (z-zoff) * zscale
yaw = atan2(y, x) * 180 / PI
if yaw < 0 then yaw = 360 + yaw
'you can eventually compute also the other axis
' pitch = (atan2(-x, sqr(y*y + z*z))) * 180 / PI
' if pitch < 0 then pitch = 360 + pitch
' roll = (atan2(y, sqr(x*x + z*z))) * 180 / PI
' if roll < 0 then roll = 360 + roll
wlog cint(yaw);"°", "Calibrated:";calib>CYCLES_TO_CALIB
calib = calib + 1
pause 100
wend
end
This is another example I did with an M5 atom matrix.
The led indicates the always NORTH position.
VID_20230430_213307.mp4
Code: [Local Link Removed for Guests]
SDA = 26
SCL = 32
I2C.SETUP SDA, SCL 'Pins as shown
neo.setup 27, 25 ' set the RGB strip
neo.strip 0,24, 0 ' clear the strip
address = &H0D ' Address of the device QMC5883
ioBuff.dim(0, 6) ' To save the measurement result
i2c.writeRegByte address, &H0A, &B10000000 ' SOFT_RST
pause 100
i2c.writeRegByte address, &H0B, 1 ' start
pause 100
'i2c.writeRegByte address, &H09, &B00000001 ' 512 samples, 2 gauss, 10Hz, continuous
i2c.writeRegByte address, &H09, &B00010001 ' 512 samples, 8 gauss, 10Hz, continuous
xmin = 1e10: xmax = -1e10
ymin = 1e10: ymax = -1e10
zmin = 1e10: zmax = -1e10
calib = 0
CYCLES_TO_CALIB = 200
while 1
i2c.read_ioBuff(0), address, &H00, 6
x = ioBuff.read(0, 0) OR (ioBuff.read(0, 1) << 8)
if x > 32768 then x = x - 65536
y = ioBuff.read(0, 2) OR (ioBuff.read(0, 3) << 8)
if y > 32768 then y = y - 65536
z = ioBuff.read(0, 4) OR (ioBuff.read(0, 5) << 8)
if z > 32768 then z = z - 65536
'wlog "x="; x, "y="; y, "z=";z
'print "xmin="; xmin, "xmax="; xmax, "ymin="; ymin, "ymax="; ymax
if ((calib> 5) and (calib< CYCLES_TO_CALIB)) then
if (x < xmin) xmin = x
if (x > xmax) xmax = x+0.1
if (y < ymin) ymin = y
if (y > ymax) ymax = y+0.1
if (z < zmin) zmin = z
if (z > zmax) zmax = z+0.1
endif
xoff = (xmax+xmin) / 2
yoff = (ymax+ymin) / 2
zoff = (zmax+zmin) / 2
xdelta = (xmax-xmin)
ydelta = (ymax-ymin)
zdelta = (zmax-zmin)
' avg_delta = (xdelta+ydelta+zdelta)/3
' xscale = avg_delta/xdelta
' yscale = avg_delta/ydelta
' zscale = avg_delta/zdelta
xscale = 1/xdelta
yscale = 1/ydelta
zscale = 1/zdelta
x = (x-xoff) * xscale
y = (y-yoff) * yscale
z = (z-zoff) * zscale
yaw = atan2(y, x) * 180 / PI
if yaw < 0 then yaw = 360 + yaw
pitch = (atan2(-x, sqr(y*y + z*z))) * 180 / PI
if pitch < 0 then pitch = 360 + pitch
roll = (atan2(y, sqr(x*x + z*z))) * 180 / PI
if roll < 0 then roll = 360 + roll
'wlog "x="; x, "y="; y, "z=";z,
'wlog cint(b1);"°", cint(b2), cint(b3), calib>CYCLES_TO_CALIB
if (calib and 1) then
wlog cint(yaw);"°", pitch, roll, calib>CYCLES_TO_CALIB
endif
calib = calib + 1
pause 100
px = cos(-yaw/180*PI)*3 + 2
py = sin(-yaw/180*PI)*3 + 2
draw_pixel px, py, 255
wend
end
sub draw_pixel x, y, col
if x < 0 then x = 0 else if x > 4 then x = 4
if y < 0 then y = 0 else if y > 4 then y = 4
neo.strip 0, 24, 0, 1 'clear all the strip without refreshing
neo.pixel cint(x) + cint(y)*5, col
end sub
You do not have the required permissions to view the files attached to this post.