MarkSherstan / MPU-6050-9250-I2C-CompFilter

MPU6050/9250 I2C and SPI interface. Sensor fusion using a complementary filter yields sensor Euler angles and is implemented in five different languages.
GNU General Public License v3.0
94 stars 24 forks source link

Note: AK8963 is set up as slave, not using direct access. #11

Closed WillemD61 closed 2 years ago

WillemD61 commented 2 years ago

You are making reference to Kris Winer's C programs. Thank you for translating these to Python so I don't have to do it myself.

It is worth noting that on Kris' site the communication with the AK8963 normally is done using direct addressing on main AK8963 address 0C. The host reads the magnometer values directly from the AK8963. The 0C address is also visible with i2cdetect.

Only in a subfolder he explains and shows the setup with the AK8963 as slave, and this is what you are using in your Python programs. This does not work on my MPU9250 and I am not sure why. (maybe it only works for MPU6050?). I am going to change it back to direct communication.

I think it is worth making a note about this in your documentation.

WillemD61 commented 2 years ago

Probably not the best way to share this, but here are the two changed methods to communicate with the AK8963 in direct access mode instead of the slave setup.

def setUpMAG(self):
    # Check to see if there is a good connection with the mag
    try:
        whoAmI = self.bus.read_byte_data(self.AK8963_ADDRESS, self.WHO_AM_I_AK8963)
    except:
        print('whoAmI MAG read failed')
        return

    if (whoAmI == 0x48):
        # Connection is good! Begin the true initialization
        self.bus.write_byte_data(self.AK8963_ADDRESS, self.AK8963_CNTL, 0x00);                      # Power down magnetometer
        time.sleep(0.05)
        self.bus.write_byte_data(self.AK8963_ADDRESS, self.AK8963_CNTL, 0x0F);                      # Enter fuze mode
        time.sleep(0.05)

        # Read the x, y, and z axis calibration values
        try:
            rawData = self.bus.read_i2c_block_data(self.AK8963_ADDRESS, self.AK8963_ASAX, 3)
        except:
            print('Reading MAG x y z calibration values failed')
            return

        # Convert values to something more usable
        self.magXcal =  float(rawData[0] - 128)/256.0 + 1.0
        self.magYcal =  float(rawData[1] - 128)/256.0 + 1.0
        self.magZcal =  float(rawData[2] - 128)/256.0 + 1.0

        self.bus.write_byte_data(self.AK8963_ADDRESS, self.AK8963_CNTL, 0x00);                      # Power down magnetometer
        # Configure the settings for the mag
        self.bus.write_byte_data(self.AK8963_ADDRESS, self.AK8963_CNTL, self.magHex);               # Set magnetometer for 14 or 16 bit continous 100 Hz sample rates
        time.sleep(0.05)

        # Display results to user
        print("MAG set up:")
        print("\tMagnetometer: " + hex(self.magHex) + " " + str(round(self.magScaleFactor,3)) + "\n")
    else:
        # Bad connection or something went wrong
        print("MAG WHO_AM_I was: " + hex(whoAmI) + ". Should have been " + hex(0x48))

def readRawMag(self):
    # Read 7 values [Low High] and one more byte (overflow check)
    try:
        rawData = self.bus.read_i2c_block_data(self.AK8963_ADDRESS, self.AK8963_XOUT_L, 7)
        #If overflow check passes convert the raw values to something a little more useful
        if not (rawData[6] & 0x08):
            self.mx = self.eightBit2sixteenBit(rawData[0], rawData[1])
            self.my = self.eightBit2sixteenBit(rawData[2], rawData[3])
            self.mz = self.eightBit2sixteenBit(rawData[4], rawData[5])  
    except:
        print('Read raw MAG data failed')
MarkSherstan commented 2 years ago

I am glad that you have found this repo helpful!

The MPU-6050 does not have a built in mag, but I have seen different behaviors depending on the breakout board used for the MPU-9250 (different pull up resistors, logic level conversion, etc...). Either way thank you for the note! I have added your methods and will complete the PR shortly.