![]() |
Forum Index : Microcontroller and PC projects : uM2(+): HMC5883 sensor calibration
Author | Message | ||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10250 |
This program generates calibration parameters for the HMC5883L magnetic sensor. To run it you need to know the magnetic field strength in your location. This site will give you that. Then run the program and rotate the sensor randomly around all axis as the program gathers data. The program will then report the multiplier in each axis that scales the measured readings to the actual field strength and also the offset of each axis about zero. In your real program you should then use the reported values to scale each axis and add in the reported offset. This should remove any fixed iron effects and improve accuracy. The program will need modification to address sensors other than the HMC5883 but the principles are the same in all cases 'Magnetometer Registers and constants
const HMC5883L_I2C = &H1E const HMC5883_MAGGAIN_4_7 = &hA0' +/- 4.7 const hmc5883_Gauss_LSB_X = 390 const hmc5883_Gauss_LSB_Y = 390 const hmc5883_Gauss_LSB_Z = 390 const GAUSS_TO_MICROTESLA = 100 Const HMC5883_CONFIG_A = 0 Const HMC5883_CONFIG_B = 1 Const HMC5883_MODE = 2 Const HMC5883_MSB_X = 3 Const HMC5883_LSB_X = 4 Const HMC5883_MSB_Y = 5 Const HMC5883_LSB_Y = 8 Const HMC5883_MSB_Z = 7 Const HMC5883_LSB_Z = 8 Const HMC5883_STATUS = 9 Const HMC5883_ID_A = 10 Const HMC5883_ID_B = 11 Const HMC5883_ID_C = 12 dim float maxx=0, minx=0, maxy=0, miny=0, maxz=0, minz=0, fields(2), x(1000),y(1000),z(1000) dim float magbias(2)=(0,0,0) dim integer iterations=1000 dim maxfield ' maximum uT reading for this location i2c open 400,1000 readByteString(HMC5883L_I2C,HMC5883_ID_A,3,ID$) if ID$<>"H43" then Print "HMC5883 not found" end endif initHMC5883 print "Rotate the sensor around all axis whilst the program is sampling" input "local field strength in uT ? ",maxfield for iterations=0 to 999 readMagData(fields()) x(iterations)=fields(0) y(iterations)=fields(1) z(iterations)=fields(2) if (iterations mod 100)=0 then print iterations/10,"% "; next iterations print "100%" floatsort(x(),1000) floatsort(y(),1000) floatsort(z(),1000) print "x-min = ",x(10)," x-max = ",x(990) print "y-min = ",y(10)," y-max = ",y(990) print "z-min = ",z(10)," z-max = ",z(990) new_hmc5883_Gauss_LSB_X = hmc5883_Gauss_LSB_X * ((abs(x(10))+abs(x(990)))/2)/maxfield 'scale at 99th percentiles new_hmc5883_Gauss_LSB_Y = hmc5883_Gauss_LSB_Y * ((abs(y(10))+abs(y(990)))/2)/maxfield new_hmc5883_Gauss_LSB_Z = hmc5883_Gauss_LSB_Z * ((abs(z(10))+abs(z(990)))/2)/maxfield print "hmc5883_Gauss_LSB_X should be ",new_hmc5883_Gauss_LSB_X print "hmc5883_Gauss_LSB_Y should be ",new_hmc5883_Gauss_LSB_Y print "hmc5883_Gauss_LSB_Z should be ",new_hmc5883_Gauss_LSB_Z print "x offset (to add) = ",((x(990)-x(10))/2-x(990))*hmc5883_Gauss_LSB_X/new_hmc5883_Gauss_LSB_X print "y offset (to add) = ",((y(990)-y(10))/2-y(990))*hmc5883_Gauss_LSB_Y/new_hmc5883_Gauss_LSB_Y print "z offset (to add) = ",((z(990)-z(10))/2-z(990))*hmc5883_Gauss_LSB_Z/new_hmc5883_Gauss_LSB_Z end sub initHMC5883() I2C WRITE HMC5883L_i2c, 0, 2, HMC5883_CONFIG_A, &h14 '1-average, 30 Hz, normal measurement I2C WRITE HMC5883L_i2c, 0, 2, HMC5883_CONFIG_B, HMC5883_MAGGAIN_4_7 'Gain=4, or any other desired gain I2C WRITE HMC5883L_i2c, 0, 2, HMC5883_MODE, &h00 'Single-measurement mode end sub sub readMagData(destination() as float) do loop while timer<(1000/30)+5 'wait to allow conversion to have taken place local integer rawData(5)' x/y/z gyro register data, ST2 register stored here, must read ST2 at end of data acquisition readBytes(HMC5883L_I2C, HMC5883_MSB_X, 6, rawData())' Read the six raw data destination(0) = (sint16((rawData(0) << 8) OR rawData(1)))/hmc5883_Gauss_LSB_X * GAUSS_TO_MICROTESLA destination(1) = (sint16((rawData(4) << 8) OR rawData(5)))/hmc5883_Gauss_LSB_Y * GAUSS_TO_MICROTESLA destination(2) = (sint16((rawData(2) << 8) OR rawData(3)))/hmc5883_Gauss_LSB_Z * GAUSS_TO_MICROTESLA timer=0 end sub FUNCTION sint16(x as integer) as float ' convert to signed 16 bit number local a%=x IF a% AND &H8000 then a%=a% OR &HFFFFFFFFFFFF0000 sint16 = a% END FUNCTION sub writeByte(address%,reg%,value%) i2c write address%,0,2,reg%,value% end sub ' function readByte(address%,reg%) as integer local r% i2c write address%,1,1,reg% i2c read address%,0,1,readByte end function ' sub readBytes(address%,reg%,n%,a%()) i2c write address%,1,1,reg% i2c read address%,0,n%,a%() end sub ' sub readByteString(address%,reg%,n%,s$) i2c write address%,1,1,reg% i2c read address%,0,n%,S$ end sub CSUB floatsort 00000000 27BDFFA8 AFBF0054 AFBE0050 AFB7004C AFB60048 AFB50044 AFB40040 AFB3003C AFB20038 AFB10034 AFB00030 AFA40058 8CA50000 AFA50018 00A09021 10000034 3C159D00 8FA20020 8C5E0000 8FA3001C 0072102A 14400019 0060B821 8FB30020 8FB10028 10000009 8FB00024 AE620000 8FA40014 02048021 02368821 02901021 0052102A 1440000C 02769821 0214B821 AFB00010 8EA20068 03C02021 0040F809 8E250000 2403FFFF 5043FFF0 8E220000 10000003 0017B880 8FB70010 0017B880 8FA40058 0097B821 AEFE0000 8FA2001C 24420001 AFA2001C 8FA30024 24630001 AFA30024 8FA40020 24840004 AFA40020 8FA20028 24420004 AFA20028 8FA30018 8FA4001C 0083102A 1440FFCF 8FA20020 001217C2 00529021 00129043 12400010 8FA30018 0243102A 1040FFFA 001217C2 0240A021 00121080 8FA40058 00821021 AFA20020 AFA40028 AFB2001C AFA00024 00121023 AFA20014 1000FFBA 0002B080 00001021 00001821 8FBF0054 8FBE0050 8FB7004C 8FB60048 8FB50044 8FB40040 8FB3003C 8FB20038 8FB10034 8FB00030 03E00008 27BD0058 End CSUB |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6270 |
My results are: Rotate the sensor around all axis whilst the program is sampling
local field strength in uT ? 61.425 0 % 10 % 20 % 30 % 40 % 50 % 60 % 70 % 80 % 90 % 100% x-min = -53.3333 x-max = 60 y-min = -71.2821 y-max = 57.1795 z-min = -56.4103 z-max = 56.4103 hmc5883_Gauss_LSB_X should be 359.788 hmc5883_Gauss_LSB_Y should be 407.814 hmc5883_Gauss_LSB_Z should be 358.16 x offset (to add) = -3.61323 y offset (to add) = 6.74326 z offset (to add) = 0 > I put these figures into my program but am still having difficulties with the tilt compensation. Too hard to be sure which way the vectors are pointing. I still need to play more with your main program. Jim VK7JH MMedit |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |