Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gy91 mpu9255 and new ak8963 #12

Open
hortovanyi opened this issue Feb 16, 2019 · 8 comments
Open

gy91 mpu9255 and new ak8963 #12

hortovanyi opened this issue Feb 16, 2019 · 8 comments

Comments

@hortovanyi
Copy link

Using a gy-91 which contains a mpu9255 and a different model AK8963

Changed in AK8963.init
if 0x48 != self.whoami:
to
if self.whoami not in (0x48,0x5F):

in AK8963.magnetic (was getting the same y an z values, appears you can no longer read six bytes at a time but must read 2 bytes for each of hxl, hyl, hzl)
So changed
xyz = list(self._register_three_shorts(_HXL)
to

x = self._register_short(_HXL)
y = self._register_short(_HYL)
z = self._register_short(_HZL)
xyz=[x,y,z]

and in mpu6500.init
if 0x71 != self.whoami
to
if self.whoami not in (0x71,0x73)

Still working away trying to get this working ...

@tuupola
Copy link
Owner

tuupola commented Feb 17, 2019

You mean this? Looks quite interesting board. Let me know how it goes.

@hortovanyi
Copy link
Author

hortovanyi commented Feb 18, 2019

Cant seem to get this to work properly .. when I plot all the graphs for calibration the data doesnt look correct. Heres the MPU-9255 register map

Sample output and the code follows

6.53933,-1.681542,-6.165654
-42.7859,-6.165654,-12.14447
-42.41222,-12.14447,-12.14447
-6.165654,-12.14447,-12.14447
-6.165654,-24.84945,-12.14447
-3.176246,-36.05973,-12.14447
-1.681542,-39.04914,-12.14447
6.913006,-41.2912,-15.13388
-37.55444,-39.04914,-12.14447
-30.82827,-24.47578,-12.14447
-36.43341,-6.165654,-12.14447
-37.74128,-5.231464,-15.13388
-42.41222,-46.89634,-12.14447
-42.7859,-46.89634,-12.14447
-0.560514,-42.22539,-12.14447
0.0,-36.43341,-12.33131
-45.77531,-30.08092,-12.14447
3.923598,17.74961,-12.14447
-42.7859,-25.59681,-6.165654
-42.7859,-27.09151,-6.165654
-42.22539,-27.09151,-6.165654
-43.90693,-30.26776,-6.165654
-43.53325,-30.08092,-6.165654
-1.681542,-30.08092,-6.165654
-3.176246,-30.82827,-6.165654
-3.176246,-30.08092,-6.165654
-3.176246,-34.9387,-6.165654
-1.681542,-30.08092,-6.165654
-3.176246,-30.08092,-6.165654
-3.176246,-36.43341,-6.165654
-6.165654,-37.55444,-6.165654
-6.165654,-40.73068,-6.165654
-6.165654,-42.7859,-6.165654
-6.165654,-0.186838,-12.14447
-6.165654,-1.681542,-6.165654
-6.165654,-6.165654,-6.165654
-12.14447,-6.165654,-6.165654
-12.14447,-12.89182,-6.165654
-12.14447,-12.14447,-6.165654
-6.165654,-12.14447,-12.14447
-6.165654,-12.14447,-12.14447
-6.165654,-24.1021,-12.14447
-3.176246,-30.08092,-12.14447
-3.176246,-30.08092,-12.14447
-0.186838,-30.08092,-12.14447
-1.681542,-30.08092,-12.14447
-45.40164,-39.04914,-12.14447
-43.72009,-39.04914,-12.14447
-37.55444,-43.53325,-12.14447
-37.55444,-45.96215,-6.165654
-37.55444,-43.90693,-12.14447
-30.08092,-42.22539,-12.14447
-30.08092,-0.560514,-12.14447
-30.82827,-45.40164,-12.14447
-27.09151,-0.93419,-6.165654
-12.14447,-0.93419,-6.165654
-12.14447,-0.93419,-6.165654
-12.14447,-0.93419,-12.14447
-12.14447,-1.681542,-12.14447
-12.14447,-0.560514,-12.14447
-6.165654,-46.52266,-12.14447
-3.176246,-46.52266,-6.165654
-1.681542,-42.7859,-12.14447
50.81994,-39.79649,-12.14447
53.062,-39.04914,-12.14447
55.11721,-33.81768,-202.7192
-30.08092,-30.08092,-250.5497
-34.9387,-24.47578,-11.02344
62.96441,-12.14447,-6.165654
-30.82827,-12.14447,-6.165654
-30.08092,-12.14447,-12.14447
-30.08092,-25.59681,-6.165654
-39.42282,-36.05973,-6.165654
48.39104,-41.2912,-6.165654
-13.63917,-1.681542,-6.165654
-12.14447,-0.93419,-6.165654
15.32072,-47.08318,-12.14447
7.47352,-44.84112,-12.14447
# Copyright (c) 2018-2019 Mika Tuupola
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of  this software and associated documentation files (the "Software"), to
# deal in  the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copied of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# https://github.com/tuupola/micropython-mpu9250
# https://www.akm.com/akm/en/file/datasheet/AK8963C.pdf

"""
MicroPython I2C driver for AK8963 magnetometer
"""

__version__ = "0.2.1"

# pylint: disable=import-error
import ustruct
import utime
from machine import I2C, Pin
from micropython import const
# pylint: enable=import-error

_WIA = const(0x00)
_INFO = const(0x01)
_ST1 = const(0x02)
_HXL = const(0x03)
_HXH = const(0x04)
_HYL = const(0x05)
_HYH = const(0x06)
_HZL = const(0x07)
_HZH = const(0x08)
_ST2 = const(0x09)
_CNTL1 = const(0x0a)
_ASAX = const(0x10)
_ASAY = const(0x11)
_ASAZ = const(0x12)

_MODE_POWER_DOWN = 0b00000000
MODE_SINGLE_MEASURE = 0b00000001
MODE_CONTINOUS_MEASURE_1 = 0b00000010 # 8Hz
MODE_CONTINOUS_MEASURE_2 = 0b00000110 # 100Hz
MODE_EXTERNAL_TRIGGER_MEASURE = 0b00000100
_MODE_SELF_TEST = 0b00001000
_MODE_FUSE_ROM_ACCESS = 0b00001111

OUTPUT_14_BIT = 0b00000000
OUTPUT_16_BIT = 0b00010000

_SO_14BIT = 0.6 # μT per digit when 14bit mode
_SO_16BIT = 4912/32760 # μT per digit when 16bit mode

DRDY = 0b00000001
DOR = 0b00000010
HOFL = 0b00001000

class AK8963:
    """Class which provides interface to AK8963 magnetometer."""
    def __init__(
        self, i2c, address=0x0c,
        mode=MODE_CONTINOUS_MEASURE_2, output=OUTPUT_16_BIT,
        offset=(0, 0, 0), scale=(1, 1, 1)
    ):
        self.i2c = i2c
        self.address = address
        self._offset = offset
        self._scale = scale

	self._raw_buf_x = bytearray(2)
	self._raw_buf_y = bytearray(2)
	self._raw_buf_z = bytearray(2)
	self._raw_xyz = [0.0,0.0,0.0]

        #if 0x48 != self.whoami:
	whoami = self.whoami
	if whoami not in (0x48,0x5F,0x7F):
            raise RuntimeError("AK8963 not found in I2C bus - found 0x%02X." % whoami)

        # Sensitivity adjustement values
        self._register_char(_CNTL1, _MODE_FUSE_ROM_ACCESS)
        asax = self._register_char(_ASAX)
        asay = self._register_char(_ASAY)
        asaz = self._register_char(_ASAZ)
        self._register_char(_CNTL1, _MODE_POWER_DOWN)

        # Should wait atleast 100us before next mode
        self._adjustement = (
            (0.5 * (asax - 128)) / 128 + 1,
            (0.5 * (asay - 128)) / 128 + 1,
            (0.5 * (asaz - 128)) / 128 + 1
        )
        utime.sleep_us(100)

        # Power on
        self._register_char(_CNTL1, (mode | output))

        if output is OUTPUT_16_BIT:
            self._so = _SO_16BIT
        else:
            self._so = _SO_14BIT

    @property
    def magnetic(self):
        """
        X, Y, Z axis micro-Tesla (uT) as floats.
        """

	while not self.data_is_ready:
	    utime.sleep_ms(10)
	    pass

	self.i2c.readfrom_mem_into(self.address, _HXL, self._raw_buf_x)
	self.i2c.readfrom_mem_into(self.address, _HYL, self._raw_buf_y)
	self.i2c.readfrom_mem_into(self.address, _HZL, self._raw_buf_z)

	if not self.magnetic_sensor_overflow:
	    self._raw_xyz[0] = self._read_int(self._raw_buf_x)
	    self._raw_xyz[1] = self._read_int(self._raw_buf_y)
	    self._raw_xyz[2] = self._read_int(self._raw_buf_z)
	    
	xyz=self._raw_xyz

        #self._register_char(_ST2) # Enable updating readings again

        # Apply factory axial sensitivy adjustements
        xyz[0] *= self._adjustement[0]
        xyz[1] *= self._adjustement[1]
        xyz[2] *= self._adjustement[2]

        # Apply output scale determined in constructor
        so = self._so
        xyz[0] *= so
        xyz[1] *= so
        xyz[2] *= so

        # Apply hard iron ie. offset bias from calibration
        xyz[0] -= self._offset[0]
        xyz[1] -= self._offset[1]
        xyz[2] -= self._offset[2]

        # Apply soft iron ie. scale bias from calibration
        xyz[0] *= self._scale[0]
        xyz[1] *= self._scale[1]
        xyz[2] *= self._scale[2]

        return tuple(xyz)

    @property
    def adjustement(self):
        return self._adjustement

    @property
    def whoami(self):
        """ Value of the whoami register. """
        return self._register_char(_WIA)

    @property
    def data_is_ready(self):
        return bool(self._register_char(_ST1) & DRDY)

    @property
    def data_overrun(self):
        return bool(self._register_char(_ST1) & DOR)

    @property
    def magnetic_sensor_overflow(self):
	return bool(self._register_char(_ST2) & HOFL)


    def calibrate(self, count=256, delay=200):
        self._offset = (0, 0, 0)
        self._scale = (1, 1, 1)

        reading = self.magnetic
        minx = maxx = reading[0]
        miny = maxy = reading[1]
        minz = maxz = reading[2]

        while count:
            utime.sleep_ms(delay)
            reading = self.magnetic
            minx = min(minx, reading[0])
            maxx = max(maxx, reading[0])
            miny = min(miny, reading[1])
            maxy = max(maxy, reading[1])
            minz = min(minz, reading[2])
            maxz = max(maxz, reading[2])
            count -= 1

        # Hard iron correction
        offset_x = (maxx + minx) / 2
        offset_y = (maxy + miny) / 2
        offset_z = (maxz + minz) / 2

        self._offset = (offset_x, offset_y, offset_z)

        # Soft iron correction
        avg_delta_x = (maxx - minx) / 2
        avg_delta_y = (maxy - miny) / 2
        avg_delta_z = (maxz - minz) / 2

        avg_delta = (avg_delta_x + avg_delta_y + avg_delta_z) / 3

        scale_x = avg_delta / avg_delta_x
        scale_y = avg_delta / avg_delta_y
        scale_z = avg_delta / avg_delta_z

        self._scale = (scale_x, scale_y, scale_z)

        return self._offset, self._scale

    def _read_int(self, buf=bytearray(2)):
	value = (buf[1] <<8) + buf[0]
	if (value >= 0x8000):
	    return -((65535 - value) + 1)
	else:
	    return value

    def _register_short(self, register, value=None, buf=bytearray(2)):
        if value is None:
            self.i2c.readfrom_mem_into(self.address, register, buf)
            return ustruct.unpack("<h", buf)[0]

        ustruct.pack_into("<h", buf, 0, value)
        return self.i2c.writeto_mem(self.address, register, buf)

    def _register_three_shorts(self, register, buf=bytearray(6)):
        self.i2c.readfrom_mem_into(self.address, register, buf)
        return ustruct.unpack("<hhh", buf)

    def _register_char(self, register, value=None, buf=bytearray(1)):
        if value is None:
            self.i2c.readfrom_mem_into(self.address, register, buf)
            return buf[0]

        ustruct.pack_into("<b", buf, 0, value)
        return self.i2c.writeto_mem(self.address, register, buf)

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        pass

@hortovanyi
Copy link
Author

Getting better data using i2c = I2C(scl=Pin(21), sda=Pin(22), freq=100000). There appears to be an issue with the default freq on an ESP32 communicating with the GY-91. Might be a timing issues?

@Tokelu
Copy link

Tokelu commented Feb 26, 2020

@hortovanyi Did you get this to work?
I have been looking into using th GY-91 with a LoPy4.
The LoPy is running µ-Python and getting the IMU to work has but me in some deep waters i have to admit, so I was looking for something to a library or driver for the GY-91

@gretel
Copy link

gretel commented Nov 25, 2020

@gretel
Copy link

gretel commented Nov 25, 2020

working fine for me using MicroPython v1.13-186-g5a7027915 on 2020-11-25; ESP module with ESP8266:

ℹ️ the gy-91 datasheet states 100 and 400khz as the only rates supported.

some seconds running:

acc (1.5275, -0.462081, 10.6111)
gyr (0.277387, 3.5177, -0.50388)
mag (10.4332, 20.6402, 1.39219)
tmp 31.0009
--
acc (-0.390255, 0.0766144, 9.69173)
gyr (0.0141225, 0.00106585, -0.0150551)
mag (12.232, 27.8824, 2.78437)
tmp 30.7134
--
acc (-0.301669, 0.0861912, 9.66539)
gyr (0.0222496, -0.0226493, -0.0159877)
mag (12.4119, 27.3392, 1.21816)
tmp 30.5217
--
acc (-0.332794, 0.100556, 9.742)
gyr (0.0209173, -0.0434334, -0.0190521)
mag (11.8723, 27.1582, 2.43633)
tmp 30.5217
--
acc (-0.28491, 0.0742202, 9.61511)
gyr (0.0182527, -0.013856, -0.0123905)
mag (13.3113, 26.434, 3.13242)
tmp 30.6654
--
acc (-0.299275, 0.083797, 9.72046)
gyr (0.0199847, -0.0110582, -0.0163874)
mag (13.3113, 26.0719, 3.13242)
tmp 30.5217
--
acc (-0.299275, 0.047884, 9.64145)
gyr (0.0225161, 0.0214502, -0.0151884)
mag (12.232, 26.434, 2.08828)
tmp 30.0904
--

@Alex-CodeLab
Copy link

Any luck with this?

I'm getting similar results, but it doesn't seem right (only the temp seems to be correct)

acce  (-0.02154782, -0.02154782, 9.289502)
gyro  (-0.05249311, 0.01985146, -0.02264931)
magn  (-12.14364, -9.666079, 7.323508)
temp  27.6463

acce  (-0.01197101, -0.06943185, 9.315839)
gyro  (-0.05342574, 0.02251608, -0.01891884)
magn  (-11.57441, -9.490331, 6.794097)
temp  27.79007

acce  (-0.01197101, -0.05027823, 9.344569)
gyro  (-0.05449158, 0.01998469, -0.02118377)
magn  (-11.76415, -10.72056, 5.911747)
temp  27.6463

acce  (-0.01197101, -0.02394202, 9.358934)
gyro  (-0.05315928, 0.02451455, -0.02251608)
magn  (-11.19492, -9.490331, 6.794097)
temp  27.79007

@ttyyzz34
Copy link

ttyyzz34 commented Apr 1, 2023

Cant seem to get this to work properly .. when I plot all the graphs for calibration the data doesnt look correct. Heres the MPU-9255 register map

Sample output and the code follows

6.53933,-1.681542,-6.165654
-42.7859,-6.165654,-12.14447
-42.41222,-12.14447,-12.14447
-6.165654,-12.14447,-12.14447
-6.165654,-24.84945,-12.14447
-3.176246,-36.05973,-12.14447
-1.681542,-39.04914,-12.14447
6.913006,-41.2912,-15.13388
-37.55444,-39.04914,-12.14447
-30.82827,-24.47578,-12.14447
-36.43341,-6.165654,-12.14447
-37.74128,-5.231464,-15.13388
-42.41222,-46.89634,-12.14447
-42.7859,-46.89634,-12.14447
-0.560514,-42.22539,-12.14447
0.0,-36.43341,-12.33131
-45.77531,-30.08092,-12.14447
3.923598,17.74961,-12.14447
-42.7859,-25.59681,-6.165654
-42.7859,-27.09151,-6.165654
-42.22539,-27.09151,-6.165654
-43.90693,-30.26776,-6.165654
-43.53325,-30.08092,-6.165654
-1.681542,-30.08092,-6.165654
-3.176246,-30.82827,-6.165654
-3.176246,-30.08092,-6.165654
-3.176246,-34.9387,-6.165654
-1.681542,-30.08092,-6.165654
-3.176246,-30.08092,-6.165654
-3.176246,-36.43341,-6.165654
-6.165654,-37.55444,-6.165654
-6.165654,-40.73068,-6.165654
-6.165654,-42.7859,-6.165654
-6.165654,-0.186838,-12.14447
-6.165654,-1.681542,-6.165654
-6.165654,-6.165654,-6.165654
-12.14447,-6.165654,-6.165654
-12.14447,-12.89182,-6.165654
-12.14447,-12.14447,-6.165654
-6.165654,-12.14447,-12.14447
-6.165654,-12.14447,-12.14447
-6.165654,-24.1021,-12.14447
-3.176246,-30.08092,-12.14447
-3.176246,-30.08092,-12.14447
-0.186838,-30.08092,-12.14447
-1.681542,-30.08092,-12.14447
-45.40164,-39.04914,-12.14447
-43.72009,-39.04914,-12.14447
-37.55444,-43.53325,-12.14447
-37.55444,-45.96215,-6.165654
-37.55444,-43.90693,-12.14447
-30.08092,-42.22539,-12.14447
-30.08092,-0.560514,-12.14447
-30.82827,-45.40164,-12.14447
-27.09151,-0.93419,-6.165654
-12.14447,-0.93419,-6.165654
-12.14447,-0.93419,-6.165654
-12.14447,-0.93419,-12.14447
-12.14447,-1.681542,-12.14447
-12.14447,-0.560514,-12.14447
-6.165654,-46.52266,-12.14447
-3.176246,-46.52266,-6.165654
-1.681542,-42.7859,-12.14447
50.81994,-39.79649,-12.14447
53.062,-39.04914,-12.14447
55.11721,-33.81768,-202.7192
-30.08092,-30.08092,-250.5497
-34.9387,-24.47578,-11.02344
62.96441,-12.14447,-6.165654
-30.82827,-12.14447,-6.165654
-30.08092,-12.14447,-12.14447
-30.08092,-25.59681,-6.165654
-39.42282,-36.05973,-6.165654
48.39104,-41.2912,-6.165654
-13.63917,-1.681542,-6.165654
-12.14447,-0.93419,-6.165654
15.32072,-47.08318,-12.14447
7.47352,-44.84112,-12.14447
# Copyright (c) 2018-2019 Mika Tuupola
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of  this software and associated documentation files (the "Software"), to
# deal in  the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copied of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# https://github.com/tuupola/micropython-mpu9250
# https://www.akm.com/akm/en/file/datasheet/AK8963C.pdf

"""
MicroPython I2C driver for AK8963 magnetometer
"""

__version__ = "0.2.1"

# pylint: disable=import-error
import ustruct
import utime
from machine import I2C, Pin
from micropython import const
# pylint: enable=import-error

_WIA = const(0x00)
_INFO = const(0x01)
_ST1 = const(0x02)
_HXL = const(0x03)
_HXH = const(0x04)
_HYL = const(0x05)
_HYH = const(0x06)
_HZL = const(0x07)
_HZH = const(0x08)
_ST2 = const(0x09)
_CNTL1 = const(0x0a)
_ASAX = const(0x10)
_ASAY = const(0x11)
_ASAZ = const(0x12)

_MODE_POWER_DOWN = 0b00000000
MODE_SINGLE_MEASURE = 0b00000001
MODE_CONTINOUS_MEASURE_1 = 0b00000010 # 8Hz
MODE_CONTINOUS_MEASURE_2 = 0b00000110 # 100Hz
MODE_EXTERNAL_TRIGGER_MEASURE = 0b00000100
_MODE_SELF_TEST = 0b00001000
_MODE_FUSE_ROM_ACCESS = 0b00001111

OUTPUT_14_BIT = 0b00000000
OUTPUT_16_BIT = 0b00010000

_SO_14BIT = 0.6 # μT per digit when 14bit mode
_SO_16BIT = 4912/32760 # μT per digit when 16bit mode

DRDY = 0b00000001
DOR = 0b00000010
HOFL = 0b00001000

class AK8963:
    """Class which provides interface to AK8963 magnetometer."""
    def __init__(
        self, i2c, address=0x0c,
        mode=MODE_CONTINOUS_MEASURE_2, output=OUTPUT_16_BIT,
        offset=(0, 0, 0), scale=(1, 1, 1)
    ):
        self.i2c = i2c
        self.address = address
        self._offset = offset
        self._scale = scale

	self._raw_buf_x = bytearray(2)
	self._raw_buf_y = bytearray(2)
	self._raw_buf_z = bytearray(2)
	self._raw_xyz = [0.0,0.0,0.0]

        #if 0x48 != self.whoami:
	whoami = self.whoami
	if whoami not in (0x48,0x5F,0x7F):
            raise RuntimeError("AK8963 not found in I2C bus - found 0x%02X." % whoami)

        # Sensitivity adjustement values
        self._register_char(_CNTL1, _MODE_FUSE_ROM_ACCESS)
        asax = self._register_char(_ASAX)
        asay = self._register_char(_ASAY)
        asaz = self._register_char(_ASAZ)
        self._register_char(_CNTL1, _MODE_POWER_DOWN)

        # Should wait atleast 100us before next mode
        self._adjustement = (
            (0.5 * (asax - 128)) / 128 + 1,
            (0.5 * (asay - 128)) / 128 + 1,
            (0.5 * (asaz - 128)) / 128 + 1
        )
        utime.sleep_us(100)

        # Power on
        self._register_char(_CNTL1, (mode | output))

        if output is OUTPUT_16_BIT:
            self._so = _SO_16BIT
        else:
            self._so = _SO_14BIT

    @property
    def magnetic(self):
        """
        X, Y, Z axis micro-Tesla (uT) as floats.
        """

	while not self.data_is_ready:
	    utime.sleep_ms(10)
	    pass

	self.i2c.readfrom_mem_into(self.address, _HXL, self._raw_buf_x)
	self.i2c.readfrom_mem_into(self.address, _HYL, self._raw_buf_y)
	self.i2c.readfrom_mem_into(self.address, _HZL, self._raw_buf_z)

	if not self.magnetic_sensor_overflow:
	    self._raw_xyz[0] = self._read_int(self._raw_buf_x)
	    self._raw_xyz[1] = self._read_int(self._raw_buf_y)
	    self._raw_xyz[2] = self._read_int(self._raw_buf_z)
	    
	xyz=self._raw_xyz

        #self._register_char(_ST2) # Enable updating readings again

        # Apply factory axial sensitivy adjustements
        xyz[0] *= self._adjustement[0]
        xyz[1] *= self._adjustement[1]
        xyz[2] *= self._adjustement[2]

        # Apply output scale determined in constructor
        so = self._so
        xyz[0] *= so
        xyz[1] *= so
        xyz[2] *= so

        # Apply hard iron ie. offset bias from calibration
        xyz[0] -= self._offset[0]
        xyz[1] -= self._offset[1]
        xyz[2] -= self._offset[2]

        # Apply soft iron ie. scale bias from calibration
        xyz[0] *= self._scale[0]
        xyz[1] *= self._scale[1]
        xyz[2] *= self._scale[2]

        return tuple(xyz)

    @property
    def adjustement(self):
        return self._adjustement

    @property
    def whoami(self):
        """ Value of the whoami register. """
        return self._register_char(_WIA)

    @property
    def data_is_ready(self):
        return bool(self._register_char(_ST1) & DRDY)

    @property
    def data_overrun(self):
        return bool(self._register_char(_ST1) & DOR)

    @property
    def magnetic_sensor_overflow(self):
	return bool(self._register_char(_ST2) & HOFL)


    def calibrate(self, count=256, delay=200):
        self._offset = (0, 0, 0)
        self._scale = (1, 1, 1)

        reading = self.magnetic
        minx = maxx = reading[0]
        miny = maxy = reading[1]
        minz = maxz = reading[2]

        while count:
            utime.sleep_ms(delay)
            reading = self.magnetic
            minx = min(minx, reading[0])
            maxx = max(maxx, reading[0])
            miny = min(miny, reading[1])
            maxy = max(maxy, reading[1])
            minz = min(minz, reading[2])
            maxz = max(maxz, reading[2])
            count -= 1

        # Hard iron correction
        offset_x = (maxx + minx) / 2
        offset_y = (maxy + miny) / 2
        offset_z = (maxz + minz) / 2

        self._offset = (offset_x, offset_y, offset_z)

        # Soft iron correction
        avg_delta_x = (maxx - minx) / 2
        avg_delta_y = (maxy - miny) / 2
        avg_delta_z = (maxz - minz) / 2

        avg_delta = (avg_delta_x + avg_delta_y + avg_delta_z) / 3

        scale_x = avg_delta / avg_delta_x
        scale_y = avg_delta / avg_delta_y
        scale_z = avg_delta / avg_delta_z

        self._scale = (scale_x, scale_y, scale_z)

        return self._offset, self._scale

    def _read_int(self, buf=bytearray(2)):
	value = (buf[1] <<8) + buf[0]
	if (value >= 0x8000):
	    return -((65535 - value) + 1)
	else:
	    return value

    def _register_short(self, register, value=None, buf=bytearray(2)):
        if value is None:
            self.i2c.readfrom_mem_into(self.address, register, buf)
            return ustruct.unpack("<h", buf)[0]

        ustruct.pack_into("<h", buf, 0, value)
        return self.i2c.writeto_mem(self.address, register, buf)

    def _register_three_shorts(self, register, buf=bytearray(6)):
        self.i2c.readfrom_mem_into(self.address, register, buf)
        return ustruct.unpack("<hhh", buf)

    def _register_char(self, register, value=None, buf=bytearray(1)):
        if value is None:
            self.i2c.readfrom_mem_into(self.address, register, buf)
            return buf[0]

        ustruct.pack_into("<b", buf, 0, value)
        return self.i2c.writeto_mem(self.address, register, buf)

    def __enter__(self):
        return self

    def __exit__(self, exception_type, exception_value, traceback):
        pass

Where did you change?I can use this code!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants