This is a simple project using the Orientation Sensor MPU9250.
This is a 9-axis device containing 3 accelerometers, 3 gyroscopes and 3 magnetometers.
The driver is written directly in Annex script but it rely on the internal fusion algorithm to compute the 3 orientation angles (pitch, roll and yaw).
The files in attachment contains all the required files for this project.
Even if not drawn on the schematics, the code drives also an OLED display that can simply connected in parallel on the same I2C pins.
Wiring
The output window
The Code
CODE: mpu9250.bas
' MPU6050 Test program
' cicciocb 2018
' the values shown are in 'g' for the accelerometers
' in °/sec for the gyros and in °C for the temperature
' in milliGauss for the Magnetometer
' important : the axis for the magnetometers different from the accelerometers and the gyros
' X magnetometer -> Y gyro + accel
' Y magnetometer -> X gyro + accel
' Z magnetometer -> -Z gyro + accel
' refer to datasheet : http://www.invensense.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf
' for the registers :
' refer to datasheet : https://www.invensense.com/wp-content/uploads/2015/02/RM-MPU-9250A-00-v1.6.pdf
MPU6050SlaveAddress = &h68
AccelScaleFactor = 32768 / 4 ' 2G full scale -- sensitivity scale factor respective to full scale setting provided in datasheet
GyroScaleFactor = 32768 / 1000' 500 °/sec full scale
MagnScaleFactor = 32768 / (10 * 4912)' 49120 milliGauss full scale
MPU6050_REG_SMPLRT_DIV = &h19
MPU6050_REG_CONFIG = &h1A
MPU6050_REG_GYRO_CONFIG = &h1B
MPU6050_REG_ACCEL_CONFIG = &h1CMPU6050_REG_FIFO_EN = &h23MPU9250_INT_PIN_CFG = &h37MPU6050_REG_INT_ENABLE = &h38MPU6050_REG_ACCEL_XOUT_H = &h3BMPU6050_REG_SIGNAL_PATH_RESET = &h68MPU6050_REG_USER_CTRL = &h6AMPU6050_REG_PWR_MGMT_1 = &h6BMPU6050_REG_PWR_MGMT_2 = &h6CMPU6050_REG_WHO_AM_I = &h75' parameters for the MPU6050 dim IMU_data(20)AccelX = 0 : AccelY = 0 : AccelZ = 0GyroX = 0: GyroY = 0: GyroZ = 0Temperature = 0'paramters for the magnetometerAK8963_ADDRESS = &h0CAK8963_WHO_AM_I = &h00AK8963_CNTL = &h0A 'Power down (0000), single-measurement (0001), self-test (1000) and Fuse ROM (1111) modes on bits 3:0AK8963_ASAX = &h10 'Fuse ROM x-axis sensitivity adjustment valuedim MAGN_data(20)dim MAGN_calib(3)MagnX = 0 : MagnY = 0 : MagnZ = 0' parameters for 6 DoF sensor fusion calculationspitch = 0 : yaw = 0 : roll = 0GyroMeasError = PI * (40.0 / 180.0) ' gyroscope measurement error in rads/s (start at 60 deg/s), then reduce after ~10 s to 3beta = sqr(3.0 / 4.0) * GyroMeasError ' compute betaGyroMeasDrift = PI * (0.0 / 180.0) ' gyroscope measurement drift in rad/s/s (start at 0.0 deg/s/s)zeta = sqr(3.0 / 4.0) * GyroMeasDrift ' compute zeta, the other free parameter in the Madgwick scheme usually set to a small or zero valuedeltat = 0.0 ' integration interval for both filter schemesdeltat_p = millis' the algo Madgwick 6 DOF uses beta and zeta (default 0.6045 , 0)' the algo Madgwick 9 DOF uses beta (default 0.6045)' the algo Mahony 9 DOF uses Kp and Ki (default = 10 , 0)beta = 0.5counter.setup 1, 12, 2fusion.initfusion.beta = betafusion.zeta = zetaonUrlMessage message'opens the html pagejscall "window.location = 'mpu6050_demo.html'"i2c.setup 4, 5'check the presence of the MPU6050ident = 0'I2C_ReadDataByte MPU6050_REG_WHO_AM_I, identident = i2c.ReadRegByte(MPU6050SlaveAddress, MPU6050_REG_WHO_AM_I)if ident <> &h71 then print "MPU9250 not found." : endMPU6050_Ini ident = i2c.ReadRegByte(AK8963_ADDRESS, AK8963_WHO_AM_I )if ident <> &h48 then print "AK8963 not found." : endAK8963_Inifor j = 1 to 1000000 i2c.readregarray MPU6050SlaveAddress, MPU6050_REG_ACCEL_XOUT_H, 14, IMU_data() ' read all registers in one shot 'extract all the parameters from the buffer extract_param AccelX, 0 extract_param AccelY, 2 extract_param AccelZ, 4 extract_param GyroX, 8 extract_param GyroY, 10 extract_param GyroZ, 12 extract_param Temperature, 6 'scale all the parameters in Engineering Unit AccelX = AccelX/AccelScaleFactor' + 0.03 AccelY = AccelY/AccelScaleFactor' + 0.01 AccelZ = AccelZ/AccelScaleFactor' + 0.08 GyroX = GyroX/GyroScaleFactor' + 0.55 GyroY = GyroY/GyroScaleFactor' + 0.8 GyroZ = GyroZ/GyroScaleFactor '- 0.25 Temperature = Temperature/340 + 36.53 ident = i2c.ReadRegByte( AK8963_ADDRESS, &h02) if (ident and 1) = 0 then print "mag data missing" i2c.readregarray AK8963_ADDRESS, &h03, 7, MAGN_data() extract_AK8963_param MagnX, 0 extract_AK8963_param MagnY, 2 extract_AK8963_param MagnZ, 4 MagnX = MagnX / MagnScaleFactor * MAGN_calib(0) MagnY = MagnY / MagnScaleFactor * MAGN_calib(1) MagnZ = MagnZ / MagnScaleFactor * MAGN_calib(2) deltat = (millis - deltat_p) / 1000 deltat_p = millis 'print deltat fusion.Madgwick AccelX, AccelY, AccelZ, (GyroX * PI/180), (GyroY * Pi/180), (GyroZ * Pi/180), MagnY, MagnX, -MagnZ 'fusion.Madgwick AccelX, AccelY, AccelZ, (GyroX * Pi/180), (GyroY * Pi/180), -(GyroZ * Pi/180) 'fusion.mahony AccelX, AccelY, AccelZ, (GyroX * Pi/180), (GyroY * Pi/180), (GyroZ * Pi/180), MagnY, MagnX, -MagnZ pitch = -fusion.angle(1) roll = fusion.angle(2) yaw = -fusion.angle(3) print str$(pitch, "%3.1f"), str$(roll, "%3.1f"), str$(yaw, "%3.1f"), deltatnext jendmessage:UrlMsgReturn str$(pitch) + "," + str$(roll) + "," + str$(yaw) + ",1" return'------------------------------------------------------------'extract a parameter from the buffer at the given address'correct the sign of the value using the Most significant bitsub extract_param(ret, address) ret = (IMU_data(address) <<8) + IMU_data(address+1) if ret > 32768 then ret = ret - 65536end sub'configuration of the MPU6050 sub MPU6050_Ini pause 150 i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_PWR_MGMT_1, &h01 'PLL with X axis gyroscope reference i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_PWR_MGMT_2, &h00 ' no sensors standby i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_SMPLRT_DIV, 9 ' sample rate = 8Khz / (1 + 7) -> 1KHz i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_CONFIG, &h01 ' bandwith 5Hz (delay 19msec) Fs 1Kz i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_GYRO_CONFIG, &h10 'set +/-1000 degree/second full scale i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_ACCEL_CONFIG, &h01 ' set +/- 4g full scale i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_FIFO_EN, &h00 ' fifo disabled 'enables the Data Ready interrupt, which occurs each 'time a write operation to all of the sensor registers has been completed. 'put a led on the pin INT to see the sample rate i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_INT_ENABLE, &h01 i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_SIGNAL_PATH_RESET, &h07 ' reset sensors i2c.WriteRegByte MPU6050SlaveAddress, MPU6050_REG_USER_CTRL, &h00 ' do not reset sensor registers (put 1 if required) i2c.WriteRegByte MPU6050SlaveAddress, MPU9250_INT_PIN_CFG, &h02 ' enable bypass mode end subsub AK8963_Ini 'First extract the factory calibration for each magnetometer axis i2c.WriteRegByte AK8963_ADDRESS, AK8963_CNTL, &h00 'Power down magnetometer pause 10 i2c.WriteRegByte AK8963_ADDRESS, AK8963_CNTL, &h0f 'Enter Fuse ROM access mode pause 10 'I2C_ReadAK8963DataByteMulti AK8963_ASAX, 3 'Read the x-, y-, and z-axis calibration values i2c.readregarray AK8963_ADDRESS, AK8963_ASAX, 3, MAGN_data() MAGN_calib(0) = (MAGN_data(0) - 128) / 256 + 1 'Return x-axis sensitivity adjustment values, etc. MAGN_calib(1) = (MAGN_data(1) - 128) / 256 + 1 MAGN_calib(2) = (MAGN_data(2) - 128) / 256 + 1 i2c.WriteRegByte AK8963_ADDRESS, AK8963_CNTL, &h00 'Power down magnetometer pause 10 'Configure the magnetometer for continuous read and highest resolution 'set Mscale bit 4 to 1 (0) to enable 16 (14) bit resolution in CNTL register, 'and enable continuous mode data acquisition Mmode (bits [3:0]), 0010 for 8 Hz and 0110 for 100 Hz sample rates i2c.WriteRegByte AK8963_ADDRESS, &h0a, &h16 ' Set magnetometer data resolution and sample ODRend sub'extract a parameter from the buffer at the given address'correct the sign of the value using the Most significant bitsub extract_AK8963_param(ret, address) ret = (MAGN_data(address+1) <<8) + MAGN_data(address) if ret > 32768 then ret = ret - 65536end sub