Read MPU6050 using ATMEGA 2560

Hi

I’m wanna get readings of gyro and accelerometer using MPU6050 sensor and atmega2560 development board.

Pin connection

VCC - 3.3V

GND - GND

SCL - SCL

SDA - SDA

  1. Set the scale of accelerometer and gyro

  2. Read raw data

  3. convert those into dps and acceleration

  4. filter accelerometer value and gyro using best filter

I tried to figure out this using many examples but still i couldn’t manage to do that. :frowning:

And i need this for my project so I will be really grateful if anyone could help me with these steps clearly

Thanks :slight_smile:

Post the code you’ve tried and “we’ll” have a look at it.

This is a very popular prgram i guess

i hv identified sm part of this code bt its nt enough to get done what i need

i havent work with arduino b4

and i’m scrambled now

plz hlp

thanks :slight_smile:

// MPU-6050 Accelerometer + Gyro + Arduino Uno

// -----------------------------

//

//

// June 2012

// Open Source / Public Domain

//

// Using Arduino 1.0.1

// It will not work with an older version,

// since Wire.endTransmission() uses a parameter

// to hold or release the I2C bus.

//

// Documentation:

// - The InvenSense documents:

// - “MPU-6000 and MPU-6050 Product Specification”,

// PS-MPU-6000A.pdf

// - “MPU-6000 and MPU-6050 Register Map and Descriptions”,

// RM-MPU-6000A.pdf or RS-MPU-6000A.pdf

// - “MPU-6000/MPU-6050 9-Axis Evaluation Board User Guide”

// AN-MPU-6000EVB.pdf

//

// The accuracy is 16-bits.

//

// Temperature sensor from -40 to +85 degrees Celsius

// 340 per degrees, -512 at 35 degrees.

//

// At power-up, all registers are zero, except these two:

// Register 0x6B (PWR_MGMT_2) = 0x40 (I read zero).

// Register 0x75 (WHO_AM_I) = 0x68.

//

#include <Wire.h>

// Register names according to the datasheet.

// According to the InvenSense document

// "MPU-6000 and MPU-6050 Register Map

// and Descriptions Revision 3.2", there are no registers

// at 0x02 … 0x18, but according other information

// the registers in that unknown area are for gain

// and offsets.

//

#define MPU6050_AUX_VDDIO 0x01 // R/W

#define MPU6050_SMPLRT_DIV 0x19 // R/W

#define MPU6050_CONFIG 0x1A // R/W

#define MPU6050_GYRO_CONFIG 0x1B // R/W

#define MPU6050_ACCEL_CONFIG 0x1C // R/W

#define MPU6050_FF_THR 0x1D // R/W

#define MPU6050_FF_DUR 0x1E // R/W

#define MPU6050_MOT_THR 0x1F // R/W

#define MPU6050_MOT_DUR 0x20 // R/W

#define MPU6050_ZRMOT_THR 0x21 // R/W

#define MPU6050_ZRMOT_DUR 0x22 // R/W

#define MPU6050_FIFO_EN 0x23 // R/W

#define MPU6050_I2C_MST_CTRL 0x24 // R/W

#define MPU6050_I2C_SLV0_ADDR 0x25 // R/W

#define MPU6050_I2C_SLV0_REG 0x26 // R/W

#define MPU6050_I2C_SLV0_CTRL 0x27 // R/W

#define MPU6050_I2C_SLV1_ADDR 0x28 // R/W

#define MPU6050_I2C_SLV1_REG 0x29 // R/W

#define MPU6050_I2C_SLV1_CTRL 0x2A // R/W

#define MPU6050_I2C_SLV2_ADDR 0x2B // R/W

#define MPU6050_I2C_SLV2_REG 0x2C // R/W

#define MPU6050_I2C_SLV2_CTRL 0x2D // R/W

#define MPU6050_I2C_SLV3_ADDR 0x2E // R/W

#define MPU6050_I2C_SLV3_REG 0x2F // R/W

#define MPU6050_I2C_SLV3_CTRL 0x30 // R/W

#define MPU6050_I2C_SLV4_ADDR 0x31 // R/W

#define MPU6050_I2C_SLV4_REG 0x32 // R/W

#define MPU6050_I2C_SLV4_DO 0x33 // R/W

#define MPU6050_I2C_SLV4_CTRL 0x34 // R/W

#define MPU6050_I2C_SLV4_DI 0x35 // R

#define MPU6050_I2C_MST_STATUS 0x36 // R

#define MPU6050_INT_PIN_CFG 0x37 // R/W

#define MPU6050_INT_ENABLE 0x38 // R/W

#define MPU6050_INT_STATUS 0x3A // R

#define MPU6050_ACCEL_XOUT_H 0x3B // R

#define MPU6050_ACCEL_XOUT_L 0x3C // R

#define MPU6050_ACCEL_YOUT_H 0x3D // R

#define MPU6050_ACCEL_YOUT_L 0x3E // R

#define MPU6050_ACCEL_ZOUT_H 0x3F // R

#define MPU6050_ACCEL_ZOUT_L 0x40 // R

#define MPU6050_TEMP_OUT_H 0x41 // R

#define MPU6050_TEMP_OUT_L 0x42 // R

#define MPU6050_GYRO_XOUT_H 0x43 // R

#define MPU6050_GYRO_XOUT_L 0x44 // R

#define MPU6050_GYRO_YOUT_H 0x45 // R

#define MPU6050_GYRO_YOUT_L 0x46 // R

#define MPU6050_GYRO_ZOUT_H 0x47 // R

#define MPU6050_GYRO_ZOUT_L 0x48 // R

#define MPU6050_EXT_SENS_DATA_00 0x49 // R

#define MPU6050_EXT_SENS_DATA_01 0x4A // R

#define MPU6050_EXT_SENS_DATA_02 0x4B // R

#define MPU6050_EXT_SENS_DATA_03 0x4C // R

#define MPU6050_EXT_SENS_DATA_04 0x4D // R

#define MPU6050_EXT_SENS_DATA_05 0x4E // R

#define MPU6050_EXT_SENS_DATA_06 0x4F // R

#define MPU6050_EXT_SENS_DATA_07 0x50 // R

#define MPU6050_EXT_SENS_DATA_08 0x51 // R

#define MPU6050_EXT_SENS_DATA_09 0x52 // R

#define MPU6050_EXT_SENS_DATA_10 0x53 // R

#define MPU6050_EXT_SENS_DATA_11 0x54 // R

#define MPU6050_EXT_SENS_DATA_12 0x55 // R

#define MPU6050_EXT_SENS_DATA_13 0x56 // R

#define MPU6050_EXT_SENS_DATA_14 0x57 // R

#define MPU6050_EXT_SENS_DATA_15 0x58 // R

#define MPU6050_EXT_SENS_DATA_16 0x59 // R

#define MPU6050_EXT_SENS_DATA_17 0x5A // R

#define MPU6050_EXT_SENS_DATA_18 0x5B // R

#define MPU6050_EXT_SENS_DATA_19 0x5C // R

#define MPU6050_EXT_SENS_DATA_20 0x5D // R

#define MPU6050_EXT_SENS_DATA_21 0x5E // R

#define MPU6050_EXT_SENS_DATA_22 0x5F // R

#define MPU6050_EXT_SENS_DATA_23 0x60 // R

#define MPU6050_MOT_DETECT_STATUS 0x61 // R

#define MPU6050_I2C_SLV0_DO 0x63 // R/W

#define MPU6050_I2C_SLV1_DO 0x64 // R/W

#define MPU6050_I2C_SLV2_DO 0x65 // R/W

#define MPU6050_I2C_SLV3_DO 0x66 // R/W

#define MPU6050_I2C_MST_DELAY_CTRL 0x67 // R/W

#define MPU6050_SIGNAL_PATH_RESET 0x68 // R/W

#define MPU6050_MOT_DETECT_CTRL 0x69 // R/W

#define MPU6050_USER_CTRL 0x6A // R/W

#define MPU6050_PWR_MGMT_1 0x6B // R/W

#define MPU6050_PWR_MGMT_2 0x6C // R/W

#define MPU6050_FIFO_COUNTH 0x72 // R/W

#define MPU6050_FIFO_COUNTL 0x73 // R/W

#define MPU6050_FIFO_R_W 0x74 // R/W

#define MPU6050_WHO_AM_I 0x75 // R

// Defines for the bits, to be able to change

// between bit number and binary definition.

// By using the bit number, programming the sensor

// is like programming the AVR microcontroller.

// But instead of using “(1<<X)”, or “_BV(X)”,

// the Arduino “bit(X)” is used.

#define MPU6050_D0 0

#define MPU6050_D1 1

#define MPU6050_D2 2

#define MPU6050_D3 3

#define MPU6050_D4 4

#define MPU6050_D5 5

#define MPU6050_D6 6

#define MPU6050_D7 7

// AUX_VDDIO Register

#define MPU6050_AUX_VDDIO MPU6050_D7 // I2C high: 1=VDD, 0=VLOGIC

// CONFIG Register

// DLPF is Digital Low Pass Filter for both gyro and accelerometers.

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_DLPF_CFG0 MPU6050_D0

#define MPU6050_DLPF_CFG1 MPU6050_D1

#define MPU6050_DLPF_CFG2 MPU6050_D2

#define MPU6050_EXT_SYNC_SET0 MPU6050_D3

#define MPU6050_EXT_SYNC_SET1 MPU6050_D4

#define MPU6050_EXT_SYNC_SET2 MPU6050_D5

// Combined definitions for the EXT_SYNC_SET values

#define MPU6050_EXT_SYNC_SET_0 (0)

#define MPU6050_EXT_SYNC_SET_1 (bit(MPU6050_EXT_SYNC_SET0))

#define MPU6050_EXT_SYNC_SET_2 (bit(MPU6050_EXT_SYNC_SET1))

#define MPU6050_EXT_SYNC_SET_3 (bit(MPU6050_EXT_SYNC_SET1)|bit(MPU6050_EXT_SYNC_SET0))

#define MPU6050_EXT_SYNC_SET_4 (bit(MPU6050_EXT_SYNC_SET2))

#define MPU6050_EXT_SYNC_SET_5 (bit(MPU6050_EXT_SYNC_SET2)|bit(MPU6050_EXT_SYNC_SET0))

#define MPU6050_EXT_SYNC_SET_6 (bit(MPU6050_EXT_SYNC_SET2)|bit(MPU6050_EXT_SYNC_SET1))

#define MPU6050_EXT_SYNC_SET_7 (bit(MPU6050_EXT_SYNC_SET2)|bit(MPU6050_EXT_SYNC_SET1)|bit(MPU6050_EXT_SYNC_SET0))

// Alternative names for the combined definitions.

#define MPU6050_EXT_SYNC_DISABLED MPU6050_EXT_SYNC_SET_0

#define MPU6050_EXT_SYNC_TEMP_OUT_L MPU6050_EXT_SYNC_SET_1

#define MPU6050_EXT_SYNC_GYRO_XOUT_L MPU6050_EXT_SYNC_SET_2

#define MPU6050_EXT_SYNC_GYRO_YOUT_L MPU6050_EXT_SYNC_SET_3

#define MPU6050_EXT_SYNC_GYRO_ZOUT_L MPU6050_EXT_SYNC_SET_4

#define MPU6050_EXT_SYNC_ACCEL_XOUT_L MPU6050_EXT_SYNC_SET_5

#define MPU6050_EXT_SYNC_ACCEL_YOUT_L MPU6050_EXT_SYNC_SET_6

#define MPU6050_EXT_SYNC_ACCEL_ZOUT_L MPU6050_EXT_SYNC_SET_7

// Combined definitions for the DLPF_CFG values

#define MPU6050_DLPF_CFG_0 (0)

#define MPU6050_DLPF_CFG_1 (bit(MPU6050_DLPF_CFG0))

#define MPU6050_DLPF_CFG_2 (bit(MPU6050_DLPF_CFG1))

#define MPU6050_DLPF_CFG_3 (bit(MPU6050_DLPF_CFG1)|bit(MPU6050_DLPF_CFG0))

#define MPU6050_DLPF_CFG_4 (bit(MPU6050_DLPF_CFG2))

#define MPU6050_DLPF_CFG_5 (bit(MPU6050_DLPF_CFG2)|bit(MPU6050_DLPF_CFG0))

#define MPU6050_DLPF_CFG_6 (bit(MPU6050_DLPF_CFG2)|bit(MPU6050_DLPF_CFG1))

#define MPU6050_DLPF_CFG_7 (bit(MPU6050_DLPF_CFG2)|bit(MPU6050_DLPF_CFG1)|bit(MPU6050_DLPF_CFG0))

// Alternative names for the combined definitions

// This name uses the bandwidth (Hz) for the accelometer,

// for the gyro the bandwidth is almost the same.

#define MPU6050_DLPF_260HZ MPU6050_DLPF_CFG_0

#define MPU6050_DLPF_184HZ MPU6050_DLPF_CFG_1

#define MPU6050_DLPF_94HZ MPU6050_DLPF_CFG_2

#define MPU6050_DLPF_44HZ MPU6050_DLPF_CFG_3

#define MPU6050_DLPF_21HZ MPU6050_DLPF_CFG_4

#define MPU6050_DLPF_10HZ MPU6050_DLPF_CFG_5

#define MPU6050_DLPF_5HZ MPU6050_DLPF_CFG_6

#define MPU6050_DLPF_RESERVED MPU6050_DLPF_CFG_7

// GYRO_CONFIG Register

// The XG_ST, YG_ST, ZG_ST are bits for selftest.

// The FS_SEL sets the range for the gyro.

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_FS_SEL0 MPU6050_D3

#define MPU6050_FS_SEL1 MPU6050_D4

#define MPU6050_ZG_ST MPU6050_D5

#define MPU6050_YG_ST MPU6050_D6

#define MPU6050_XG_ST MPU6050_D7

// Combined definitions for the FS_SEL values

#define MPU6050_FS_SEL_0 (0)

#define MPU6050_FS_SEL_1 (bit(MPU6050_FS_SEL0))

#define MPU6050_FS_SEL_2 (bit(MPU6050_FS_SEL1))

#define MPU6050_FS_SEL_3 (bit(MPU6050_FS_SEL1)|bit(MPU6050_FS_SEL0))

// Alternative names for the combined definitions

// The name uses the range in degrees per second.

#define MPU6050_FS_SEL_250 MPU6050_FS_SEL_0

#define MPU6050_FS_SEL_500 MPU6050_FS_SEL_1

#define MPU6050_FS_SEL_1000 MPU6050_FS_SEL_2

#define MPU6050_FS_SEL_2000 MPU6050_FS_SEL_3

// ACCEL_CONFIG Register

// The XA_ST, YA_ST, ZA_ST are bits for selftest.

// The AFS_SEL sets the range for the accelerometer.

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_ACCEL_HPF0 MPU6050_D0

#define MPU6050_ACCEL_HPF1 MPU6050_D1

#define MPU6050_ACCEL_HPF2 MPU6050_D2

#define MPU6050_AFS_SEL0 MPU6050_D3

#define MPU6050_AFS_SEL1 MPU6050_D4

#define MPU6050_ZA_ST MPU6050_D5

#define MPU6050_YA_ST MPU6050_D6

#define MPU6050_XA_ST MPU6050_D7

// Combined definitions for the ACCEL_HPF values

#define MPU6050_ACCEL_HPF_0 (0)

#define MPU6050_ACCEL_HPF_1 (bit(MPU6050_ACCEL_HPF0))

#define MPU6050_ACCEL_HPF_2 (bit(MPU6050_ACCEL_HPF1))

#define MPU6050_ACCEL_HPF_3 (bit(MPU6050_ACCEL_HPF1)|bit(MPU6050_ACCEL_HPF0))

#define MPU6050_ACCEL_HPF_4 (bit(MPU6050_ACCEL_HPF2))

#define MPU6050_ACCEL_HPF_7 (bit(MPU6050_ACCEL_HPF2)|bit(MPU6050_ACCEL_HPF1)|bit(MPU6050_ACCEL_HPF0))

// Alternative names for the combined definitions

// The name uses the Cut-off frequency.

#define MPU6050_ACCEL_HPF_RESET MPU6050_ACCEL_HPF_0

#define MPU6050_ACCEL_HPF_5HZ MPU6050_ACCEL_HPF_1

#define MPU6050_ACCEL_HPF_2_5HZ MPU6050_ACCEL_HPF_2

#define MPU6050_ACCEL_HPF_1_25HZ MPU6050_ACCEL_HPF_3

#define MPU6050_ACCEL_HPF_0_63HZ MPU6050_ACCEL_HPF_4

#define MPU6050_ACCEL_HPF_HOLD MPU6050_ACCEL_HPF_7

// Combined definitions for the AFS_SEL values

#define MPU6050_AFS_SEL_0 (0)

#define MPU6050_AFS_SEL_1 (bit(MPU6050_AFS_SEL0))

#define MPU6050_AFS_SEL_2 (bit(MPU6050_AFS_SEL1))

#define MPU6050_AFS_SEL_3 (bit(MPU6050_AFS_SEL1)|bit(MPU6050_AFS_SEL0))

// Alternative names for the combined definitions

// The name uses the full scale range for the accelerometer.

#define MPU6050_AFS_SEL_2G MPU6050_AFS_SEL_0

#define MPU6050_AFS_SEL_4G MPU6050_AFS_SEL_1

#define MPU6050_AFS_SEL_8G MPU6050_AFS_SEL_2

#define MPU6050_AFS_SEL_16G MPU6050_AFS_SEL_3

// FIFO_EN Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_SLV0_FIFO_EN MPU6050_D0

#define MPU6050_SLV1_FIFO_EN MPU6050_D1

#define MPU6050_SLV2_FIFO_EN MPU6050_D2

#define MPU6050_ACCEL_FIFO_EN MPU6050_D3

#define MPU6050_ZG_FIFO_EN MPU6050_D4

#define MPU6050_YG_FIFO_EN MPU6050_D5

#define MPU6050_XG_FIFO_EN MPU6050_D6

#define MPU6050_TEMP_FIFO_EN MPU6050_D7

// I2C_MST_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_MST_CLK0 MPU6050_D0

#define MPU6050_I2C_MST_CLK1 MPU6050_D1

#define MPU6050_I2C_MST_CLK2 MPU6050_D2

#define MPU6050_I2C_MST_CLK3 MPU6050_D3

#define MPU6050_I2C_MST_P_NSR MPU6050_D4

#define MPU6050_SLV_3_FIFO_EN MPU6050_D5

#define MPU6050_WAIT_FOR_ES MPU6050_D6

#define MPU6050_MULT_MST_EN MPU6050_D7

// Combined definitions for the I2C_MST_CLK

#define MPU6050_I2C_MST_CLK_0 (0)

#define MPU6050_I2C_MST_CLK_1 (bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_2 (bit(MPU6050_I2C_MST_CLK1))

#define MPU6050_I2C_MST_CLK_3 (bit(MPU6050_I2C_MST_CLK1)|bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_4 (bit(MPU6050_I2C_MST_CLK2))

#define MPU6050_I2C_MST_CLK_5 (bit(MPU6050_I2C_MST_CLK2)|bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_6 (bit(MPU6050_I2C_MST_CLK2)|bit(MPU6050_I2C_MST_CLK1))

#define MPU6050_I2C_MST_CLK_7 (bit(MPU6050_I2C_MST_CLK2)|bit(MPU6050_I2C_MST_CLK1)|bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_8 (bit(MPU6050_I2C_MST_CLK3))

#define MPU6050_I2C_MST_CLK_9 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_10 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK1))

#define MPU6050_I2C_MST_CLK_11 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK1)|bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_12 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK2))

#define MPU6050_I2C_MST_CLK_13 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK2)|bit(MPU6050_I2C_MST_CLK0))

#define MPU6050_I2C_MST_CLK_14 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK2)|bit(MPU6050_I2C_MST_CLK1))

#define MPU6050_I2C_MST_CLK_15 (bit(MPU6050_I2C_MST_CLK3)|bit(MPU6050_I2C_MST_CLK2)|bit(MPU6050_I2C_MST_CLK1)|bit(MPU6050_I2C_MST_CLK0))

// Alternative names for the combined definitions

// The names uses I2C Master Clock Speed in kHz.

#define MPU6050_I2C_MST_CLK_348KHZ MPU6050_I2C_MST_CLK_0

#define MPU6050_I2C_MST_CLK_333KHZ MPU6050_I2C_MST_CLK_1

#define MPU6050_I2C_MST_CLK_320KHZ MPU6050_I2C_MST_CLK_2

#define MPU6050_I2C_MST_CLK_308KHZ MPU6050_I2C_MST_CLK_3

#define MPU6050_I2C_MST_CLK_296KHZ MPU6050_I2C_MST_CLK_4

#define MPU6050_I2C_MST_CLK_286KHZ MPU6050_I2C_MST_CLK_5

#define MPU6050_I2C_MST_CLK_276KHZ MPU6050_I2C_MST_CLK_6

#define MPU6050_I2C_MST_CLK_267KHZ MPU6050_I2C_MST_CLK_7

#define MPU6050_I2C_MST_CLK_258KHZ MPU6050_I2C_MST_CLK_8

#define MPU6050_I2C_MST_CLK_500KHZ MPU6050_I2C_MST_CLK_9

#define MPU6050_I2C_MST_CLK_471KHZ MPU6050_I2C_MST_CLK_10

#define MPU6050_I2C_MST_CLK_444KHZ MPU6050_I2C_MST_CLK_11

#define MPU6050_I2C_MST_CLK_421KHZ MPU6050_I2C_MST_CLK_12

#define MPU6050_I2C_MST_CLK_400KHZ MPU6050_I2C_MST_CLK_13

#define MPU6050_I2C_MST_CLK_381KHZ MPU6050_I2C_MST_CLK_14

#define MPU6050_I2C_MST_CLK_364KHZ MPU6050_I2C_MST_CLK_15

// I2C_SLV0_ADDR Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV0_RW MPU6050_D7

// I2C_SLV0_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV0_LEN0 MPU6050_D0

#define MPU6050_I2C_SLV0_LEN1 MPU6050_D1

#define MPU6050_I2C_SLV0_LEN2 MPU6050_D2

#define MPU6050_I2C_SLV0_LEN3 MPU6050_D3

#define MPU6050_I2C_SLV0_GRP MPU6050_D4

#define MPU6050_I2C_SLV0_REG_DIS MPU6050_D5

#define MPU6050_I2C_SLV0_BYTE_SW MPU6050_D6

#define MPU6050_I2C_SLV0_EN MPU6050_D7

// A mask for the length

#define MPU6050_I2C_SLV0_LEN_MASK 0x0F

// I2C_SLV1_ADDR Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV1_RW MPU6050_D7

// I2C_SLV1_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV1_LEN0 MPU6050_D0

#define MPU6050_I2C_SLV1_LEN1 MPU6050_D1

#define MPU6050_I2C_SLV1_LEN2 MPU6050_D2

#define MPU6050_I2C_SLV1_LEN3 MPU6050_D3

#define MPU6050_I2C_SLV1_GRP MPU6050_D4

#define MPU6050_I2C_SLV1_REG_DIS MPU6050_D5

#define MPU6050_I2C_SLV1_BYTE_SW MPU6050_D6

#define MPU6050_I2C_SLV1_EN MPU6050_D7

// A mask for the length

#define MPU6050_I2C_SLV1_LEN_MASK 0x0F

// I2C_SLV2_ADDR Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV2_RW MPU6050_D7

// I2C_SLV2_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV2_LEN0 MPU6050_D0

#define MPU6050_I2C_SLV2_LEN1 MPU6050_D1

#define MPU6050_I2C_SLV2_LEN2 MPU6050_D2

#define MPU6050_I2C_SLV2_LEN3 MPU6050_D3

#define MPU6050_I2C_SLV2_GRP MPU6050_D4

#define MPU6050_I2C_SLV2_REG_DIS MPU6050_D5

#define MPU6050_I2C_SLV2_BYTE_SW MPU6050_D6

#define MPU6050_I2C_SLV2_EN MPU6050_D7

// A mask for the length

#define MPU6050_I2C_SLV2_LEN_MASK 0x0F

// I2C_SLV3_ADDR Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV3_RW MPU6050_D7

// I2C_SLV3_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV3_LEN0 MPU6050_D0

#define MPU6050_I2C_SLV3_LEN1 MPU6050_D1

#define MPU6050_I2C_SLV3_LEN2 MPU6050_D2

#define MPU6050_I2C_SLV3_LEN3 MPU6050_D3

#define MPU6050_I2C_SLV3_GRP MPU6050_D4

#define MPU6050_I2C_SLV3_REG_DIS MPU6050_D5

#define MPU6050_I2C_SLV3_BYTE_SW MPU6050_D6

#define MPU6050_I2C_SLV3_EN MPU6050_D7

// A mask for the length

#define MPU6050_I2C_SLV3_LEN_MASK 0x0F

// I2C_SLV4_ADDR Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV4_RW MPU6050_D7

// I2C_SLV4_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_MST_DLY0 MPU6050_D0

#define MPU6050_I2C_MST_DLY1 MPU6050_D1

#define MPU6050_I2C_MST_DLY2 MPU6050_D2

#define MPU6050_I2C_MST_DLY3 MPU6050_D3

#define MPU6050_I2C_MST_DLY4 MPU6050_D4

#define MPU6050_I2C_SLV4_REG_DIS MPU6050_D5

#define MPU6050_I2C_SLV4_INT_EN MPU6050_D6

#define MPU6050_I2C_SLV4_EN MPU6050_D7

// A mask for the delay

#define MPU6050_I2C_MST_DLY_MASK 0x1F

// I2C_MST_STATUS Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV0_NACK MPU6050_D0

#define MPU6050_I2C_SLV1_NACK MPU6050_D1

#define MPU6050_I2C_SLV2_NACK MPU6050_D2

#define MPU6050_I2C_SLV3_NACK MPU6050_D3

#define MPU6050_I2C_SLV4_NACK MPU6050_D4

#define MPU6050_I2C_LOST_ARB MPU6050_D5

#define MPU6050_I2C_SLV4_DONE MPU6050_D6

#define MPU6050_PASS_THROUGH MPU6050_D7

// I2C_PIN_CFG Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_CLKOUT_EN MPU6050_D0

#define MPU6050_I2C_BYPASS_EN MPU6050_D1

#define MPU6050_FSYNC_INT_EN MPU6050_D2

#define MPU6050_FSYNC_INT_LEVEL MPU6050_D3

#define MPU6050_INT_RD_CLEAR MPU6050_D4

#define MPU6050_LATCH_INT_EN MPU6050_D5

#define MPU6050_INT_OPEN MPU6050_D6

#define MPU6050_INT_LEVEL MPU6050_D7

// INT_ENABLE Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_DATA_RDY_EN MPU6050_D0

#define MPU6050_I2C_MST_INT_EN MPU6050_D3

#define MPU6050_FIFO_OFLOW_EN MPU6050_D4

#define MPU6050_ZMOT_EN MPU6050_D5

#define MPU6050_MOT_EN MPU6050_D6

#define MPU6050_FF_EN MPU6050_D7

// INT_STATUS Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_DATA_RDY_INT MPU6050_D0

#define MPU6050_I2C_MST_INT MPU6050_D3

#define MPU6050_FIFO_OFLOW_INT MPU6050_D4

#define MPU6050_ZMOT_INT MPU6050_D5

#define MPU6050_MOT_INT MPU6050_D6

#define MPU6050_FF_INT MPU6050_D7

// MOT_DETECT_STATUS Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_MOT_ZRMOT MPU6050_D0

#define MPU6050_MOT_ZPOS MPU6050_D2

#define MPU6050_MOT_ZNEG MPU6050_D3

#define MPU6050_MOT_YPOS MPU6050_D4

#define MPU6050_MOT_YNEG MPU6050_D5

#define MPU6050_MOT_XPOS MPU6050_D6

#define MPU6050_MOT_XNEG MPU6050_D7

// IC2_MST_DELAY_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_I2C_SLV0_DLY_EN MPU6050_D0

#define MPU6050_I2C_SLV1_DLY_EN MPU6050_D1

#define MPU6050_I2C_SLV2_DLY_EN MPU6050_D2

#define MPU6050_I2C_SLV3_DLY_EN MPU6050_D3

#define MPU6050_I2C_SLV4_DLY_EN MPU6050_D4

#define MPU6050_DELAY_ES_SHADOW MPU6050_D7

// SIGNAL_PATH_RESET Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_TEMP_RESET MPU6050_D0

#define MPU6050_ACCEL_RESET MPU6050_D1

#define MPU6050_GYRO_RESET MPU6050_D2

// MOT_DETECT_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_MOT_COUNT0 MPU6050_D0

#define MPU6050_MOT_COUNT1 MPU6050_D1

#define MPU6050_FF_COUNT0 MPU6050_D2

#define MPU6050_FF_COUNT1 MPU6050_D3

#define MPU6050_ACCEL_ON_DELAY0 MPU6050_D4

#define MPU6050_ACCEL_ON_DELAY1 MPU6050_D5

// Combined definitions for the MOT_COUNT

#define MPU6050_MOT_COUNT_0 (0)

#define MPU6050_MOT_COUNT_1 (bit(MPU6050_MOT_COUNT0))

#define MPU6050_MOT_COUNT_2 (bit(MPU6050_MOT_COUNT1))

#define MPU6050_MOT_COUNT_3 (bit(MPU6050_MOT_COUNT1)|bit(MPU6050_MOT_COUNT0))

// Alternative names for the combined definitions

#define MPU6050_MOT_COUNT_RESET MPU6050_MOT_COUNT_0

// Combined definitions for the FF_COUNT

#define MPU6050_FF_COUNT_0 (0)

#define MPU6050_FF_COUNT_1 (bit(MPU6050_FF_COUNT0))

#define MPU6050_FF_COUNT_2 (bit(MPU6050_FF_COUNT1))

#define MPU6050_FF_COUNT_3 (bit(MPU6050_FF_COUNT1)|bit(MPU6050_FF_COUNT0))

// Alternative names for the combined definitions

#define MPU6050_FF_COUNT_RESET MPU6050_FF_COUNT_0

// Combined definitions for the ACCEL_ON_DELAY

#define MPU6050_ACCEL_ON_DELAY_0 (0)

#define MPU6050_ACCEL_ON_DELAY_1 (bit(MPU6050_ACCEL_ON_DELAY0))

#define MPU6050_ACCEL_ON_DELAY_2 (bit(MPU6050_ACCEL_ON_DELAY1))

#define MPU6050_ACCEL_ON_DELAY_3 (bit(MPU6050_ACCEL_ON_DELAY1)|bit(MPU6050_ACCEL_ON_DELAY0))

// Alternative names for the ACCEL_ON_DELAY

#define MPU6050_ACCEL_ON_DELAY_0MS MPU6050_ACCEL_ON_DELAY_0

#define MPU6050_ACCEL_ON_DELAY_1MS MPU6050_ACCEL_ON_DELAY_1

#define MPU6050_ACCEL_ON_DELAY_2MS MPU6050_ACCEL_ON_DELAY_2

#define MPU6050_ACCEL_ON_DELAY_3MS MPU6050_ACCEL_ON_DELAY_3

// USER_CTRL Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_SIG_COND_RESET MPU6050_D0

#define MPU6050_I2C_MST_RESET MPU6050_D1

#define MPU6050_FIFO_RESET MPU6050_D2

#define MPU6050_I2C_IF_DIS MPU6050_D4 // must be 0 for MPU-6050

#define MPU6050_I2C_MST_EN MPU6050_D5

#define MPU6050_FIFO_EN MPU6050_D6

// PWR_MGMT_1 Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_CLKSEL0 MPU6050_D0

#define MPU6050_CLKSEL1 MPU6050_D1

#define MPU6050_CLKSEL2 MPU6050_D2

#define MPU6050_TEMP_DIS MPU6050_D3 // 1: disable temperature sensor

#define MPU6050_CYCLE MPU6050_D5 // 1: sample and sleep

#define MPU6050_SLEEP MPU6050_D6 // 1: sleep mode

#define MPU6050_DEVICE_RESET MPU6050_D7 // 1: reset to default values

// Combined definitions for the CLKSEL

#define MPU6050_CLKSEL_0 (0)

#define MPU6050_CLKSEL_1 (bit(MPU6050_CLKSEL0))

#define MPU6050_CLKSEL_2 (bit(MPU6050_CLKSEL1))

#define MPU6050_CLKSEL_3 (bit(MPU6050_CLKSEL1)|bit(MPU6050_CLKSEL0))

#define MPU6050_CLKSEL_4 (bit(MPU6050_CLKSEL2))

#define MPU6050_CLKSEL_5 (bit(MPU6050_CLKSEL2)|bit(MPU6050_CLKSEL0))

#define MPU6050_CLKSEL_6 (bit(MPU6050_CLKSEL2)|bit(MPU6050_CLKSEL1))

#define MPU6050_CLKSEL_7 (bit(MPU6050_CLKSEL2)|bit(MPU6050_CLKSEL1)|bit(MPU6050_CLKSEL0))

// Alternative names for the combined definitions

#define MPU6050_CLKSEL_INTERNAL MPU6050_CLKSEL_0

#define MPU6050_CLKSEL_X MPU6050_CLKSEL_1

#define MPU6050_CLKSEL_Y MPU6050_CLKSEL_2

#define MPU6050_CLKSEL_Z MPU6050_CLKSEL_3

#define MPU6050_CLKSEL_EXT_32KHZ MPU6050_CLKSEL_4

#define MPU6050_CLKSEL_EXT_19_2MHZ MPU6050_CLKSEL_5

#define MPU6050_CLKSEL_RESERVED MPU6050_CLKSEL_6

#define MPU6050_CLKSEL_STOP MPU6050_CLKSEL_7

// PWR_MGMT_2 Register

// These are the names for the bits.

// Use these only with the bit() macro.

#define MPU6050_STBY_ZG MPU6050_D0

#define MPU6050_STBY_YG MPU6050_D1

#define MPU6050_STBY_XG MPU6050_D2

#define MPU6050_STBY_ZA MPU6050_D3

#define MPU6050_STBY_YA MPU6050_D4

#define MPU6050_STBY_XA MPU6050_D5

#define MPU6050_LP_WAKE_CTRL0 MPU6050_D6

#define MPU6050_LP_WAKE_CTRL1 MPU6050_D7

// Combined definitions for the LP_WAKE_CTRL

#define MPU6050_LP_WAKE_CTRL_0 (0)

#define MPU6050_LP_WAKE_CTRL_1 (bit(MPU6050_LP_WAKE_CTRL0))

#define MPU6050_LP_WAKE_CTRL_2 (bit(MPU6050_LP_WAKE_CTRL1))

#define MPU6050_LP_WAKE_CTRL_3 (bit(MPU6050_LP_WAKE_CTRL1)|bit(MPU6050_LP_WAKE_CTRL0))

// Alternative names for the combined definitions

// The names uses the Wake-up Frequency.

#define MPU6050_LP_WAKE_1_25HZ MPU6050_LP_WAKE_CTRL_0

#define MPU6050_LP_WAKE_2_5HZ MPU6050_LP_WAKE_CTRL_1

#define MPU6050_LP_WAKE_5HZ MPU6050_LP_WAKE_CTRL_2

#define MPU6050_LP_WAKE_10HZ MPU6050_LP_WAKE_CTRL_3

// Default I2C address for the MPU-6050 is 0x68.

// But only if the AD0 pin is low.

// Some sensor boards have AD0 high, and the

// I2C address thus becomes 0x69.

#define MPU6050_I2C_ADDRESS 0x68

// Declaring an union for the registers and the axis values.

// The byte order does not match the byte order of

// the compiler and AVR chip.

// The AVR chip (on the Arduino board) has the Low Byte

// at the lower address.

// But the MPU-6050 has a different order: High Byte at

// lower address, so that has to be corrected.

// The register part “reg” is only used internally,

// and are swapped in code.

typedef union accel_t_gyro_union

{

struct

{

uint8_t x_accel_h;

uint8_t x_accel_l;

uint8_t y_accel_h;

uint8_t y_accel_l;

uint8_t z_accel_h;

uint8_t z_accel_l;

uint8_t t_h;

uint8_t t_l;

uint8_t x_gyro_h;

uint8_t x_gyro_l;

uint8_t y_gyro_h;

uint8_t y_gyro_l;

uint8_t z_gyro_h;

uint8_t z_gyro_l;

} reg;

struct

{

int x_accel;

int y_accel;

int z_accel;

int temperature;

int x_gyro;

int y_gyro;

int z_gyro;

} value;

};

// Use the following global variables and access functions to help store the overall

// rotation angle of the sensor

unsigned long last_read_time;

float last_x_angle; // These are the filtered angles

float last_y_angle;

float last_z_angle;

float last_gyro_x_angle; // Store the gyro angles to compare drift

float last_gyro_y_angle;

float last_gyro_z_angle;

float last_x_kalangle; //Kalman angle

float last_y_kalangle;

float last_z_kalangle;

void set_last_read_angle_data(unsigned long time, float x, float y, float z, float x_gyro, float y_gyro, float z_gyro, float kx, float ky, float kz) {

last_read_time = time;

last_x_angle = x;

last_y_angle = y;

last_z_angle = z;

last_gyro_x_angle = x_gyro;

last_gyro_y_angle = y_gyro;

last_gyro_z_angle = z_gyro;

last_x_kalangle = kx;

last_y_kalangle = ky;

last_z_kalangle = kz;

}

inline unsigned long get_last_time() {return last_read_time;}

inline float get_last_x_angle() {return last_x_angle;}

inline float get_last_y_angle() {return last_y_angle;}

inline float get_last_z_angle() {return last_z_angle;}

inline float get_last_gyro_x_angle() {return last_gyro_x_angle;}

inline float get_last_gyro_y_angle() {return last_gyro_y_angle;}

inline float get_last_gyro_z_angle() {return last_gyro_z_angle;}

inline float get_last_x_kalangle() {return last_x_kalangle;}

inline float get_last_y_kalangle() {return last_y_kalangle;}

inline float get_last_z_kalangle() {return last_z_kalangle;}

// Use the following global variables and access functions

// to calibrate the acceleration sensor

float base_x_accel;

float base_y_accel;

float base_z_accel;

float base_x_gyro;

float base_y_gyro;

float base_z_gyro;

int read_gyro_accel_vals(uint8_t* accel_t_gyro_ptr) {

// Read the raw values.

// Read 14 bytes at once,

// containing acceleration, temperature and gyro.

// With the default settings of the MPU-6050,

// there is no filter enabled, and the values

// are not very stable. Returns the error value

accel_t_gyro_union* accel_t_gyro = (accel_t_gyro_union *) accel_t_gyro_ptr;

int error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) accel_t_gyro, sizeof(*accel_t_gyro));

// Swap all high and low bytes.

// After this, the registers values are swapped,

// so the structure name like x_accel_l does no

// longer contain the lower byte.

uint8_t swap;

#define SWAP(x,y) swap = x; x = y; y = swap

SWAP ((*accel_t_gyro).reg.x_accel_h, (*accel_t_gyro).reg.x_accel_l);

SWAP ((*accel_t_gyro).reg.y_accel_h, (*accel_t_gyro).reg.y_accel_l);

SWAP ((*accel_t_gyro).reg.z_accel_h, (*accel_t_gyro).reg.z_accel_l);

SWAP ((*accel_t_gyro).reg.t_h, (*accel_t_gyro).reg.t_l);

SWAP ((*accel_t_gyro).reg.x_gyro_h, (*accel_t_gyro).reg.x_gyro_l);

SWAP ((*accel_t_gyro).reg.y_gyro_h, (*accel_t_gyro).reg.y_gyro_l);

SWAP ((*accel_t_gyro).reg.z_gyro_h, (*accel_t_gyro).reg.z_gyro_l);

return error;

}

// The sensor should be motionless on a horizontal surface

// while calibration is happening

void calibrate_sensors() {

int num_readings = 10;

float x_accel = 0;

float y_accel = 0;

float z_accel = 0;

float x_gyro = 0;

float y_gyro = 0;

float z_gyro = 0;

accel_t_gyro_union accel_t_gyro;

//Serial.println(“Starting Calibration”);

// Discard the first set of values read from the IMU

read_gyro_accel_vals((uint8_t *) &accel_t_gyro);

// Read and average the raw values from the IMU

for (int i = 0; i < num_readings; i++) {

read_gyro_accel_vals((uint8_t *) &accel_t_gyro);

x_accel += accel_t_gyro.value.x_accel;

y_accel += accel_t_gyro.value.y_accel;

z_accel += accel_t_gyro.value.z_accel;

x_gyro += accel_t_gyro.value.x_gyro;

y_gyro += accel_t_gyro.value.y_gyro;

z_gyro += accel_t_gyro.value.z_gyro;

delay(100);

}

x_accel /= num_readings;

y_accel /= num_readings;

z_accel /= num_readings;

x_gyro /= num_readings;

y_gyro /= num_readings;

z_gyro /= num_readings;

// Store the raw calibration values globally

base_x_accel = x_accel;

base_y_accel = y_accel;

base_z_accel = z_accel;

base_x_gyro = x_gyro;

base_y_gyro = y_gyro;

base_z_gyro = z_gyro;

//Serial.println(“Finishing Calibration”);

}

/************************

  • KALMAN - Filter setup *

*************************/

class Kalman {

public:

Kalman() {

/* We will set the varibles like so, these can also be tuned by the user */

Q_angle = 0.001;

Q_bias = 0.003;

R_measure = 0.03;

bias = 0; // Reset bias

P[0][0] = 0; // Since we assume tha the bias is 0 and we know the starting angle (use setAngle), the error covariance matrix is set like so - see: http://en.wikipedia.org/wiki/Kalman_fil … _technical

P[0][1] = 0;

P[1][0] = 0;

P[1][1] = 0;

};

// The angle should be in degrees and the rate should be in degrees per second and the delta time in seconds

float getAngle(float newAngle, float newRate, float dt) {

// KasBot V2 - Kalman filter module - http://www.x-firm.com/?page_id=145

// Modified by Kristian Lauszus

// See my blog post for more information: http://blog.tkjelectronics.dk/2012/09/a … plement-it

// Discrete Kalman filter time update equations - Time Update (“Predict”)

// Update xhat - Project the state ahead

/* Step 1 */

rate = newRate - bias;

angle += dt * rate;

// Update estimation error covariance - Project the error covariance ahead

/* Step 2 */

P[0][0] += dt * (dt*P[1][1] - P[0][1] - P[1][0] + Q_angle);

P[0][1] -= dt * P[1][1];

P[1][0] -= dt * P[1][1];

P[1][1] += Q_bias * dt;

// Discrete Kalman filter measurement update equations - Measurement Update (“Correct”)

// Calculate Kalman gain - Compute the Kalman gain

/* Step 4 */

S = P[0][0] + R_measure;

/* Step 5 */

K[0] = P[0][0] / S;

K[1] = P[1][0] / S;

// Calculate angle and bias - Update estimate with measurement zk (newAngle)

/* Step 3 */

y = newAngle - angle;

/* Step 6 */

angle += K[0] * y;

bias += K[1] * y;

// Calculate estimation error covariance - Update the error covariance

/* Step 7 */

P[0][0] -= K[0] * P[0][0];

P[0][1] -= K[0] * P[0][1];

P[1][0] -= K[1] * P[0][0];

P[1][1] -= K[1] * P[0][1];

return angle;

};

void setAngle(double newAngle) { angle = newAngle; }; // Used to set angle, this should be set as the starting angle

double getRate() { return rate; }; // Return the unbiased rate

/* These are used to tune the Kalman filter */

void setQangle(double newQ_angle) { Q_angle = newQ_angle; };

void setQbias(double newQ_bias) { Q_bias = newQ_bias; };

void setRmeasure(double newR_measure) { R_measure = newR_measure; };

double getQangle() { return Q_angle; };

double getQbias() { return Q_bias; };

double getRmeasure() { return R_measure; };

private:

/* Kalman filter variables */

double Q_angle; // Process noise variance for the accelerometer

double Q_bias; // Process noise variance for the gyro bias

double R_measure; // Measurement noise variance - this is actually the variance of the measurement noise

double angle; // The angle calculated by the Kalman filter - part of the 2x1 state matrix

double bias; // The gyro bias calculated by the Kalman filter - part of the 2x1 state matrix

double rate; // Unbiased rate calculated from the rate and the calculated bias - you have to call getAngle to update the rate

double P[2][2]; // Error covariance matrix - This is a 2x2 matrix

double K[2]; // Kalman gain - This is a 2x1 matrix

double y; // Angle difference - 1x1 matrix

double S; // Estimate error - 1x1 matrix

};

Kalman kalmanX; // Create the Kalman instances

Kalman kalmanY;

/********

  • SETUP *

*********/

void setup()

{

int error;

uint8_t c;

accel_t_gyro_union accel_t_gyro;

Serial.begin(19200);

// Initialize the ‘Wire’ class for the I2C-bus.

Wire.begin();

// default at power-up:

// Gyro at 250 degrees second

// Acceleration at 2g

// Clock source at internal 8MHz

// The device is in sleep mode.

//

error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);

// According to the datasheet, the ‘sleep’ bit

// should read a ‘1’. But I read a ‘0’.

// That bit has to be cleared, since the sensor

// is in sleep mode at power-up. Even if the

// bit reads ‘0’.

error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1);

// Clear the ‘sleep’ bit to start the sensor.

MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);

//Initialize the angles

calibrate_sensors();

set_last_read_angle_data(millis(), 0, 0, 0, 0, 0, 0, 0, 0, 0);

// Get raw acceleration values

//float G_CONVERT = 16384;

float accel_x = accel_t_gyro.value.x_accel;

float accel_y = accel_t_gyro.value.y_accel;

float accel_z = accel_t_gyro.value.z_accel;

// Get angle values from accelerometer

float RADIANS_TO_DEGREES = 180/3.14159;

// float accel_vector_length = sqrt(pow(accel_x,2) + pow(accel_y,2) + pow(accel_z,2));

float accel_angle_x = atan(accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;

float accel_angle_y = atan(-1*accel_x/sqrt(pow(accel_y,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;

float accel_angle_z = 0;

kalmanX.setAngle(accel_angle_x); // Set starting angle

kalmanY.setAngle(accel_angle_y);

}

/************

  • Main loop *

*************/

void loop()

{

int error;

double dT;

accel_t_gyro_union accel_t_gyro;

float kalAngleX, kalAngleY, kalAngleZ; // Calculate the angle using a Kalman filter

// Read the raw values.

error = read_gyro_accel_vals((uint8_t*) &accel_t_gyro);

// Get the time of reading for rotation computations

unsigned long t_now = millis();

// Convert gyro values to degrees/sec

float FS_SEL = 131;

float gyro_x = (accel_t_gyro.value.x_gyro - base_x_gyro)/FS_SEL;

float gyro_y = (accel_t_gyro.value.y_gyro - base_y_gyro)/FS_SEL;

float gyro_z = (accel_t_gyro.value.z_gyro - base_z_gyro)/FS_SEL;

// Get raw acceleration values

//float G_CONVERT = 16384;

float accel_x = accel_t_gyro.value.x_accel;

float accel_y = accel_t_gyro.value.y_accel;

float accel_z = accel_t_gyro.value.z_accel;

// Get angle values from accelerometer

float RADIANS_TO_DEGREES = 180/3.14159;

//float accel_vector_length = sqrt(pow(accel_x,2) + pow(accel_y,2) + pow(accel_z,2));

float accel_angle_y = atan(-1*accel_x/sqrt(pow(accel_y,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;

float accel_angle_x = atan(accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;

float accel_angle_z = 0;

// Compute the (filtered) gyro angles

float dt =(t_now - get_last_time())/1000.0;

float gyro_angle_x = gyro_x*dt ;//+ get_last_x_angle();

float gyro_angle_y = gyro_y*dt; //+ get_last_y_angle();

float gyro_angle_z = gyro_z*dt ;//+ get_last_z_angle();

// Compute the drifting gyro angles

float unfiltered_gyro_angle_x = gyro_x*dt; //+ get_last_gyro_x_angle();

float unfiltered_gyro_angle_y = gyro_y*dt; //+ get_last_gyro_y_angle();

float unfiltered_gyro_angle_z = gyro_z*dt;// + get_last_gyro_z_angle();

// Apply the complementary filter to figure out the change in angle - choice of alpha is

// estimated now. Alpha depends on the sampling rate…

float alpha = 0.96;

float angle_x = alpha*gyro_angle_x + (1.0 - alpha)*accel_angle_x;

float angle_y = alpha*gyro_angle_y + (1.0 - alpha)*accel_angle_y;

float angle_z = gyro_angle_z; //Accelerometer doesn’t give z-angle

//KALMAN filter

kalAngleX = kalmanX.getAngle(accel_angle_x, gyro_x, dt);

//delay(5);

kalAngleY = kalmanY.getAngle(accel_angle_y, gyro_y, dt);

kalAngleZ = gyro_angle_z;

// Update the saved data with the latest values

set_last_read_angle_data(t_now, angle_x, angle_y, angle_z, unfiltered_gyro_angle_x, unfiltered_gyro_angle_y, unfiltered_gyro_angle_z, kalAngleX, kalAngleY, kalAngleZ);

//Note added: 10/08/13 pad() creates padding that is required to ensure 128Bytes are sent. May not be needed as new version of LV code maybe able to handle

//Serial.print(“START”);

//Send the data to the serial port

Serial.print(F(“DEL:”)); //Delta T

Serial.print(dt, DEC);

Serial.print(F(“#ACC:”)); //Accelerometer angle

pad(accel_angle_x);

//Serial.print(accel_angle_x, 2);

Serial.print(F(“,”));

pad(accel_angle_y);

//Serial.print(accel_angle_y, 2);

Serial.print(F(“,”));

pad(accel_angle_z);

//Serial.print(accel_angle_z, 2);

Serial.print(F(“#GYR:”));

pad(unfiltered_gyro_angle_x);

//Serial.print(unfiltered_gyro_angle_x, 2); //Gyroscope angle

Serial.print(F(“,”));

pad(unfiltered_gyro_angle_y);

//Serial.print(unfiltered_gyro_angle_y, 2);

Serial.print(F(“,”));

pad(unfiltered_gyro_angle_z);

//Serial.print(unfiltered_gyro_angle_z, 2);

Serial.print(F(“#FIL:”)); //Filtered angle

pad(angle_x);

//Serial.print(angle_x, 2);

Serial.print(F(“,”));

pad(angle_y);

//Serial.print(angle_y, 2);

Serial.print(F(“,”));

pad(angle_z);

//Serial.print(angle_z, 2);

Serial.print(F(“,”));

Serial.print(F(“#KAL:”)); //Kalman Filtered angle

pad(kalAngleX);

//Serial.print(kalAngleX, 2);

Serial.print(F(“,”));

pad (kalAngleY);

//Serial.print(kalAngleY, 2);

Serial.print(F(“,”));

pad(kalAngleZ);

//Serial.print(kalAngleZ, 2);

//Serial.print(“END”);

Serial.print(“\n”);

//Serial.println(F(“”));

Serial.flush();

// Delay so we don’t swamp the serial port

delay(5); //so not to swamp the serial port

}

// --------------------------------------------------------

// MPU6050_read

//

// This is a common function to read multiple bytes

// from an I2C device.

//

// It uses the boolean parameter for Wire.endTransMission()

// to be able to hold or release the I2C-bus.

// This is implemented in Arduino 1.0.1.

//

// Only this function is used to read.

// There is no function for a single byte.

//

int MPU6050_read(int start, uint8_t *buffer, int size)

{

int i, n, error;

Wire.beginTransmission(MPU6050_I2C_ADDRESS);

n = Wire.write(start);

if (n != 1)

return (-10);

n = Wire.endTransmission(false); // hold the I2C-bus

if (n != 0)

return (n);

// Third parameter is true: relase I2C-bus after data is read.

Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);

i = 0;

while(Wire.available() && i<size)

{

buffer[i++]=Wire.read();

}

if ( i != size)

return (-11);

return (0); // return : no error

}

// --------------------------------------------------------

// MPU6050_write

//

// This is a common function to write multiple bytes to an I2C device.

//

// If only a single register is written,

// use the function MPU_6050_write_reg().

//

// Parameters:

// start : Start address, use a define for the register

// pData : A pointer to the data to write.

// size : The number of bytes to write.

//

// If only a single register is written, a pointer

// to the data has to be used, and the size is

// a single byte:

// int data = 0; // the data to write

// MPU6050_write (MPU6050_PWR_MGMT_1, &c, 1);

//

int MPU6050_write(int start, const uint8_t *pData, int size)

{

int n, error;

Wire.beginTransmission(MPU6050_I2C_ADDRESS);

n = Wire.write(start); // write the start address

if (n != 1)

return (-20);

n = Wire.write(pData, size); // write data bytes

if (n != size)

return (-21);

error = Wire.endTransmission(true); // release the I2C-bus

if (error != 0)

return (error);

return (0); // return : no error

}

// --------------------------------------------------------

// MPU6050_write_reg

//

// An extra function to write a single register.

// It is just a wrapper around the MPU_6050_write()

// function, and it is only a convenient function

// to make it easier to write a single register.

//

int MPU6050_write_reg(int reg, uint8_t data)

{

int error;

error = MPU6050_write(reg, &data, 1);

return (error);

}

//This function pads the printed value to take up

//7 characters Example: **20.16

void pad(float PadVal){

//Positve Value

if (PadVal > 0){ //For positive value

if(PadVal < 10){ //For positive value less than 10

Serial.print(“***”); //0-9 ***0-9.00

}

else if (PadVal < 100){ //values less than 100

Serial.print(“**”); //10-99 **10-99.00

}

}

else if(PadVal < 0){ //for negative values

if(PadVal > -10){ //for negative value greater than -10

Serial.print(“**”); //-9 - 0 **-1 - -9.00

}

else if (PadVal > -100){ //for negative values lesss than -99

Serial.print(""); //-99.00

}

}

Serial.print(PadVal, 2); //print the padded value

}

Hashan123:
This is a very popular prgram i guess

i hv identified sm part of this code bt its nt enough to get done what i need

It's not enough to read and filter the values ? It seems more than complete to me. What, specifically, have you found not working ? I'd break the program down and, if you haven't already, very that the I2C communications bus is working. Do this with a simple program reading, and sending to the serial monitor, the following 2 registers;

Register 0x6B

Register 0x75

// At power-up, all registers are zero, except these two:

// Register 0x6B (PWR_MGMT_2) = 0x40 (I read zero).

// Register 0x75 (WHO_AM_I) = 0x68.

If those agree with the values above, then the comm channel is working. When that’s working then you can write (or copy) a small portion of code to read the raw values.

6B is PWR_MGMT_1

Do u want me to do device reset?

i think it is :slight_smile:

What I want you to do is super-simplify the code to just read those 2 registers and report the values read back from the 6050. We can progress fairly quickly from there.

What I suspect is that your school homework is late because you’ve not bothered to do it and now you’re looking for someone to bail you out. I hope I am wrong. Prove me wrong.

:confused:

wait

i havent done this b4

and i have lot of questions

can i use I2C hat used in above code to read those 2 registers?

coz I cant understand that read function I’m trying my best

tks

Hashan123:
i havent done this b4

You need to read at least these pages then;

http://arduino.cc/en/Tutorial/Foundations

http://arduino.cc/en/Tutorial/Sketch

http://arduino.cc/en/Tutorial/Variables

http://arduino.cc/en/Reference/Setup

http://arduino.cc/en/Reference/Loop

http://arduino.cc/en/Reference/FunctionDeclaration

http://arduino.cc/en/Reference/HomePage

http://www.arduino.cc/en/Reference/Wire

http://en.wikipedia.org/wiki/I%C2%B2C

:slight_smile:

tks

and i have to say I’m nt searching one for bail me out

i hv to do lot of thing after get those reading

the hard part is for me is get readings from the sensor

and i hv time too :slight_smile:

nrmally i finish my work quickly so i started my work early than my batch mates :slight_smile:

Hashan123:
the hard part is for me is get readings from the sensor

See if you can follow this …

RE: reading the raw data from the 6050. That’s done in the loop(), in the last line of the snippet below.

/************
* Main loop *
*************/
void loop()
{
  int error;
  double dT;
  accel_t_gyro_union accel_t_gyro;

  float kalAngleX, kalAngleY, kalAngleZ; // Calculate the angle using a Kalman filter

  // Read the raw values.
  error = read_gyro_accel_vals((uint8_t*) &accel_t_gyro);

The reading is done by the function read_gyro_accel_vals(), which seems to return some error indication to determine if the reading was done successfully or not. But where did the data from the 6050 go ? Let’s look at that function to see what it does.

int read_gyro_accel_vals(uint8_t* accel_t_gyro_ptr) {
  // Read the raw values.
  // Read 14 bytes at once,
  // containing acceleration, temperature and gyro.
  // With the default settings of the MPU-6050,
  // there is no filter enabled, and the values
  // are not very stable. Returns the error value

  accel_t_gyro_union* accel_t_gyro = (accel_t_gyro_union *) accel_t_gyro_ptr;

  int error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) accel_t_gyro, sizeof(*accel_t_gyro));

  // Swap all high and low bytes.
  // After this, the registers values are swapped,
  // so the structure name like x_accel_l does no
  // longer contain the lower byte.
  uint8_t swap;
#define SWAP(x,y) swap = x; x = y; y = swap

  SWAP ((*accel_t_gyro).reg.x_accel_h, (*accel_t_gyro).reg.x_accel_l);
  SWAP ((*accel_t_gyro).reg.y_accel_h, (*accel_t_gyro).reg.y_accel_l);
  SWAP ((*accel_t_gyro).reg.z_accel_h, (*accel_t_gyro).reg.z_accel_l);
  SWAP ((*accel_t_gyro).reg.t_h, (*accel_t_gyro).reg.t_l);
  SWAP ((*accel_t_gyro).reg.x_gyro_h, (*accel_t_gyro).reg.x_gyro_l);
  SWAP ((*accel_t_gyro).reg.y_gyro_h, (*accel_t_gyro).reg.y_gyro_l);
  SWAP ((*accel_t_gyro).reg.z_gyro_h, (*accel_t_gyro).reg.z_gyro_l);

  return error;

There’s a lot going on there but we can see there’s yet another function called, MPU6050_read().

to do the actual I2C reading. Reading the 6050 datasheet you know the 14 bit raw data values come

across the I2C bus as two separate 7 bit values and those need to be re-combined back into a 14 bit value

stored in a 16 bit word. While the code uses pointers and a structure that may be hard for you to figure

out ATM, you can probably see the high and low bytes being swapped and thus recombined as mentioned. These are stored in memory in a ordered fashion (a structure) so perhaps we’ll look at the structure (strictly speaking a union). It’s named accel_t_gyro. Let’s look at it.

// Declaring an union for the registers and the axis values.
// The byte order does not match the byte order of
// the compiler and AVR chip.
// The AVR chip (on the Arduino board) has the Low Byte
// at the lower address.
// But the MPU-6050 has a different order: High Byte at
// lower address, so that has to be corrected.
// The register part "reg" is only used internally,
// and are swapped in code.
typedef union accel_t_gyro_union
{
  struct
  {
    uint8_t x_accel_h;
    uint8_t x_accel_l;
    uint8_t y_accel_h;
    uint8_t y_accel_l;
    uint8_t z_accel_h;
    uint8_t z_accel_l;
    uint8_t t_h;
    uint8_t t_l;
    uint8_t x_gyro_h;
    uint8_t x_gyro_l;
    uint8_t y_gyro_h;
    uint8_t y_gyro_l;
    uint8_t z_gyro_h;
    uint8_t z_gyro_l;
  } reg;
  struct
  {
    int x_accel;
    int y_accel;
    int z_accel;
    int temperature;
    int x_gyro;
    int y_gyro;
    int z_gyro;
  } value;
};

We can see there’s places for the high and low bytes of the accel, temp and gyro data. You might also

guess that the recombined raw data is stored in the locations named at the bottom. Keep those in mind

and let’s now go back to the main loop(), but down a few lines from the prior snippet.

  // Convert gyro values to degrees/sec
  float FS_SEL = 131;

  float gyro_x = (accel_t_gyro.value.x_gyro - base_x_gyro) / FS_SEL;
  float gyro_y = (accel_t_gyro.value.y_gyro - base_y_gyro) / FS_SEL;
  float gyro_z = (accel_t_gyro.value.z_gyro - base_z_gyro) / FS_SEL;

Here we see the raw 16 bit data for the gyro being converted into floating point (FP) variables that have

units of degrees/second. Look at the variable names used. It’s the union/structure name followed by a .value.

and then followed by the names noted above. It’s a fair bet that these variables;

accel_t_gyro.value.x_gyro
accel_t_gyro.value.y_gyro
accel_t_gyro.value.z_gyro

… hold the raw gyro data you’re looking for. Similarly you can find the raw data for the accel X, Y and Z.

Having read all the links I posted you should be able to understand variable names and functions and the general layout of the code. If you want, Google about C/C++ pointers and structures, to better understand the above. But there’s your raw data, if you care to print it out. Though perhaps the scaled (deg/sec) FP values would be easier to understand.

:slight_smile:

thanks a lot for ur help

i was confused about that high byte and low byte thing

thanks to u nw i know what happens in there :slight_smile:

great

nw i have to deal with the filter

as for the filter which filter would be good,

Kalman or complementary ?

the code i used here has used kalman filter but i checked with that unfiltered gyro values

which i noted is unfiltered gyro values are accurate than kalman filter values :confused:

and also I need to know what how can i change the scale of the gyro :slight_smile:

I tried it but i dont see a change

tks :slight_smile:

Re: filtering … it all depends on your needs. Kalman is computationally intensive, complementary not so much. Here’s one article you may find interesting.

http://www.pieter-jan.com/node/11

There is no “best” way.

and also I need to know what how can i change the scale of the gyro :slight_smile:

I tried it but i dont see a change

Since I have no idea what you did, kinda hard to offer any help. Post your code.

ps - (click on to open)

OK thanks :slight_smile:

i’m going to detect the orientation of a vehicle and by that I want to find a way to driver’s driving behavior

// Combined definitions for the FS_SEL values
#define MPU6050_FS_SEL_0 (0)
#define MPU6050_FS_SEL_1 (bit(MPU6050_FS_SEL0))
#define MPU6050_FS_SEL_2 (bit(MPU6050_FS_SEL1))
#define MPU6050_FS_SEL_3 (bit(MPU6050_FS_SEL1)|bit(MPU6050_FS_SEL0))

// Alternative names for the combined definitions
// The name uses the range in degrees per second.
#define MPU6050_FS_SEL_250  MPU6050_FS_SEL_0
#define MPU6050_FS_SEL_500  MPU6050_FS_SEL_1
#define MPU6050_FS_SEL_1000 MPU6050_FS_SEL_2
#define MPU6050_FS_SEL_2000 MPU6050_FS_SEL_3

/*
Those were define on top of the code i used
*/

void setup()
{      
  int error;
  uint8_t c;
  accel_t_gyro_union accel_t_gyro;

/*1st attempt
  mpu.setFullScaleAccelRange(MPU6050_FS_SEL_3);
*/

/*
2nd attempt
MPU6050_FS_SEL_3;
*/

/*and many I cant remember other things i tried
coz i tried it month ago*/


  Serial.begin(19200);
  
  // Initialize the 'Wire' class for the I2C-bus.
  Wire.begin();


  // default at power-up:
  //    Gyro at 250 degrees second
  //    Acceleration at 2g
  //    Clock source at internal 8MHz
  //    The device is in sleep mode.
  //

  error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);
  

  // According to the datasheet, the 'sleep' bit
  // should read a '1'. But I read a '0'.
  // That bit has to be cleared, since the sensor
  // is in sleep mode at power-up. Even if the
  // bit reads '0'.
  error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1);
  
  // Clear the 'sleep' bit to start the sensor.
  MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);
  
  //Initialize the angles
  calibrate_sensors();  
  set_last_read_angle_data(millis(), 0, 0, 0, 0, 0, 0, 0, 0, 0);
  
  
  // Get raw acceleration values
  //float G_CONVERT = 16384;
  float accel_x = accel_t_gyro.value.x_accel;
  float accel_y = accel_t_gyro.value.y_accel;
  float accel_z = accel_t_gyro.value.z_accel;
  
  // Get angle values from accelerometer
  float RADIANS_TO_DEGREES = 180/3.14159;
//  float accel_vector_length = sqrt(pow(accel_x,2) + pow(accel_y,2) + pow(accel_z,2));
  float accel_angle_x = atan(accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;
  float accel_angle_y = atan(-1*accel_x/sqrt(pow(accel_y,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;


  float accel_angle_z = 0;
  
  kalmanX.setAngle(accel_angle_x); // Set starting angle
  kalmanY.setAngle(accel_angle_y);

}

Do you think it might be a good idea to write to the gyro scale factor register after you’ve done the wake-up routine ?

  // Clear the 'sleep' bit to start the sensor.
  MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);

Also have you verified that you have good communications to/from the 6050 ?

Lastly … does your code compile w/o errors ?

And it occurs to me from …

i’m going to detect the orientation of a vehicle and by that I want to find a way to driver’s driving behavior

… that you’re trying to measure real cars w/real drivers and not race cars nor RC cars nor anything else. If that’s true, why would you want to increase the range of the gyro ? I doubt any normal car driven will ever exceed a 250 deg/sec turning rate. At a car’s minimum turning diameter, the tightest circle it can turn, it would require a speed of ~60 MPH and have the car pulling >10G’s lateral acceleration. That’s just not possible. How sure are you that the vehicle you’re measuring could ever get to, let alone exceed, 250 deg/sec ? If it can’t do that then why increase the dynamic range and reduce the sensitivity ?

oh I asked hlp from local ppl that i know and they said increasing the scale will be increase sensitivity

I also doubt abt that :slight_smile:

Tks for the hlp :slight_smile:

then from now i need to deal with a filter

Hi,

I have a small issue

when I read our MPU6050 sensor without moving (in idle state on my table) it produces a garbage value in random time.

so I’m more than happy if anyone can help me out with this trouble.

the code shown below is the code that I’m using

// At power-up, all registers are zero, except these two:
//      Register 0x6B (PWR_MGMT_2) = 0x40  (I read zero).
//      Register 0x75 (WHO_AM_I)   = 0x68.


#include <Wire.h>

// Register names according to the datasheet.
// According to the InvenSense document 
// "MPU-6000 and MPU-6050 Register Map 
// and Descriptions Revision 3.2", there are no registers
// at 0x02 ... 0x18, but according other information 
// the registers in that unknown area are for gain 
// and offsets.

#define MPU6050_ACCEL_XOUT_H       0x3B   // R  
#define MPU6050_PWR_MGMT_1         0x6B   // R/W
#define MPU6050_PWR_MGMT_2         0x6C   // R/W
#define MPU6050_WHO_AM_I           0x75   // R


// Default I2C address for the MPU-6050 is 0x68.
// But only if the AD0 pin is low.
// Some sensor boards have AD0 high, and the
// I2C address thus becomes 0x69.
#define MPU6050_I2C_ADDRESS 0x68


// Declaring an union for the registers and the axis values.
// The byte order does not match the byte order of 
// the compiler and AVR chip.
// The AVR chip (on the Arduino board) has the Low Byte 
// at the lower address.
// But the MPU-6050 has a different order: High Byte at
// lower address, so that has to be corrected.
// The register part "reg" is only used internally, 
// and are swapped in code.
typedef union accel_t_gyro_union
{
  struct
  {
    uint8_t x_accel_h;
    uint8_t x_accel_l;
    uint8_t y_accel_h;
    uint8_t y_accel_l;
    uint8_t z_accel_h;
    uint8_t z_accel_l;
    uint8_t t_h;
    uint8_t t_l;
    uint8_t x_gyro_h;
    uint8_t x_gyro_l;
    uint8_t y_gyro_h;
    uint8_t y_gyro_l;
    uint8_t z_gyro_h;
    uint8_t z_gyro_l;
  } 
  reg;
  struct 
  {
    int x_accel;
    int y_accel;
    int z_accel;
    int temperature;
    int x_gyro;
    int y_gyro;
    int z_gyro;
  } 
  value;
};

// Use the following global variables and access functions to help store the overall
// rotation angle of the sensor
unsigned long last_read_time;
float         last_x_angle;  // These are the filtered angles
float         last_y_angle;
float         last_z_angle;  
float         last_gyro_x_angle;  // Store the gyro angles to compare drift
float         last_gyro_y_angle;
float         last_gyro_z_angle;


void set_last_read_angle_data(unsigned long time, float x, float y, float z, float x_gyro, float y_gyro, float z_gyro) {
  last_read_time = time;
  last_x_angle = x;
  last_y_angle = y;
  last_z_angle = z;
  last_gyro_x_angle = x_gyro;
  last_gyro_y_angle = y_gyro;
  last_gyro_z_angle = z_gyro;
}

inline unsigned long get_last_time() {
  return last_read_time;
}
inline float get_last_x_angle() {
  return last_x_angle;
}
inline float get_last_y_angle() {
  return last_y_angle;
}
inline float get_last_z_angle() {
  return last_z_angle;
}
inline float get_last_gyro_x_angle() {
  return last_gyro_x_angle;
}
inline float get_last_gyro_y_angle() {
  return last_gyro_y_angle;
}
inline float get_last_gyro_z_angle() {
  return last_gyro_z_angle;
}


//  Use the following global variables and access functions
//  to calibrate the acceleration sensor
float    base_x_accel;
float    base_y_accel;
float    base_z_accel;

float    base_x_gyro;
float    base_y_gyro;
float    base_z_gyro;


int read_gyro_accel_vals(uint8_t* accel_t_gyro_ptr) {
  // Read the raw values.
  // Read 14 bytes at once, 
  // containing acceleration, temperature and gyro.
  // With the default settings of the MPU-6050,
  // there is no filter enabled, and the values
  // are not very stable.  Returns the error value

  accel_t_gyro_union* accel_t_gyro = (accel_t_gyro_union *) accel_t_gyro_ptr;
 
  int error = MPU6050_read (MPU6050_ACCEL_XOUT_H, (uint8_t *) accel_t_gyro, sizeof(*accel_t_gyro));

  // Swap all high and low bytes.
  // After this, the registers values are swapped, 
  // so the structure name like x_accel_l does no 
  // longer contain the lower byte.
  uint8_t swap;
#define SWAP(x,y) swap = x; x = y; y = swap

  SWAP ((*accel_t_gyro).reg.x_accel_h, (*accel_t_gyro).reg.x_accel_l);
  SWAP ((*accel_t_gyro).reg.y_accel_h, (*accel_t_gyro).reg.y_accel_l);
  SWAP ((*accel_t_gyro).reg.z_accel_h, (*accel_t_gyro).reg.z_accel_l);
  SWAP ((*accel_t_gyro).reg.t_h, (*accel_t_gyro).reg.t_l);
  SWAP ((*accel_t_gyro).reg.x_gyro_h, (*accel_t_gyro).reg.x_gyro_l);
  SWAP ((*accel_t_gyro).reg.y_gyro_h, (*accel_t_gyro).reg.y_gyro_l);
  SWAP ((*accel_t_gyro).reg.z_gyro_h, (*accel_t_gyro).reg.z_gyro_l);

  return error;
}

// The sensor should be motionless on a horizontal surface 
//  while calibration is happening
void calibrate_sensors() {
  int                   num_readings = 10;
  float                 x_accel = 0;
  float                 y_accel = 0;
  float                 z_accel = 0;
  float                 x_gyro = 0;
  float                 y_gyro = 0;
  float                 z_gyro = 0;
  accel_t_gyro_union    accel_t_gyro;

  //Serial.println("Starting Calibration");

  // Discard the first set of values read from the IMU
  read_gyro_accel_vals((uint8_t *) &accel_t_gyro);

  // Read and average the raw values from the IMU
  for (int i = 0; i < num_readings; i++) {
    read_gyro_accel_vals((uint8_t *) &accel_t_gyro);
    x_accel += accel_t_gyro.value.x_accel;
    y_accel += accel_t_gyro.value.y_accel;
    z_accel += accel_t_gyro.value.z_accel;
    x_gyro += accel_t_gyro.value.x_gyro;
    y_gyro += accel_t_gyro.value.y_gyro;
    z_gyro += accel_t_gyro.value.z_gyro;
    delay(100);
  }
  x_accel /= num_readings;
  y_accel /= num_readings;
  z_accel /= num_readings;
  x_gyro /= num_readings;
  y_gyro /= num_readings;
  z_gyro /= num_readings;

  // Store the raw calibration values globally
  base_x_accel = x_accel;
  base_y_accel = y_accel;
  base_z_accel = z_accel;
  base_x_gyro = x_gyro;
  base_y_gyro = y_gyro;
  base_z_gyro = z_gyro;

  //Serial.println("Finishing Calibration");
}

/********
 * SETUP *
 *********/

void setup()
{      
  int error;
  uint8_t c;
  accel_t_gyro_union accel_t_gyro;


  //Serial.begin(19200);
  Serial.begin(19200);

  // Initialize the 'Wire' class for the I2C-bus.
  Wire.begin();

  // default at power-up:
  //    Gyro at 250 degrees second
  //    Acceleration at 2g
  //    Clock source at internal 8MHz
  //    The device is in sleep mode.
  //

  error = MPU6050_read (MPU6050_WHO_AM_I, &c, 1);

  // According to the datasheet, the 'sleep' bit
  // should read a '1'. But I read a '0'.
  // That bit has to be cleared, since the sensor
  // is in sleep mode at power-up. Even if the
  // bit reads '0'.
  error = MPU6050_read (MPU6050_PWR_MGMT_2, &c, 1);

  // Clear the 'sleep' bit to start the sensor.
  MPU6050_write_reg (MPU6050_PWR_MGMT_1, 0);

  //Initialize the angles
  calibrate_sensors();  
  set_last_read_angle_data(millis(), 0, 0, 0, 0, 0, 0);


  // Get raw acceleration values
  //float G_CONVERT = 16384;
  float accel_x = accel_t_gyro.value.x_accel;
  float accel_y = accel_t_gyro.value.y_accel;
  float accel_z = accel_t_gyro.value.z_accel;

  // Get angle values from accelerometer
  float RADIANS_TO_DEGREES = 180/3.14159;
  //  float accel_vector_length = sqrt(pow(accel_x,2) + pow(accel_y,2) + pow(accel_z,2));
  float accel_angle_x = atan(accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;
  float accel_angle_y = atan(-1*accel_x/sqrt(pow(accel_y,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;


  float accel_angle_z = 0;

}

void(* resetFunc) (void) = 0; //declare reset function @ address 0


/************
 * Main loop *
 *************/
void loop()
{
  int error;
  double dT;
  accel_t_gyro_union accel_t_gyro;

  //float kalAngleX, kalAngleY, kalAngleZ; // Calculate the angle using a Kalman filter

  // Read the raw values.
  error = read_gyro_accel_vals((uint8_t*) &accel_t_gyro);

  // Get the time of reading for rotation computations
  unsigned long t_now = millis();


  // Convert gyro values to degrees/sec
  float FS_SEL = 131;

  float gyro_x = (accel_t_gyro.value.x_gyro - base_x_gyro)/FS_SEL;
  float gyro_y = (accel_t_gyro.value.y_gyro - base_y_gyro)/FS_SEL;
  float gyro_z = (accel_t_gyro.value.z_gyro - base_z_gyro)/FS_SEL;


  // Get raw acceleration values
  //float G_CONVERT = 16384;
  float accel_x = accel_t_gyro.value.x_accel;
  float accel_y = accel_t_gyro.value.y_accel;
  float accel_z = accel_t_gyro.value.z_accel;

  // Get angle values from accelerometer
  float RADIANS_TO_DEGREES = 180/3.14159;
  //float accel_vector_length = sqrt(pow(accel_x,2) + pow(accel_y,2) + pow(accel_z,2));
  
  float accel_angle_y = atan(-1*accel_x/sqrt(pow(accel_y,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;
  float accel_angle_x = atan(accel_y/sqrt(pow(accel_x,2) + pow(accel_z,2)))*RADIANS_TO_DEGREES;

  float accel_angle_z = 0;

  float dt =(t_now - get_last_time())/1000.0;

  // Update the saved data with the latest values
  //set_last_read_angle_data(t_now, angle_x, angle_y, angle_z, unfiltered_gyro_angle_x, unfiltered_gyro_angle_y, unfiltered_gyro_angle_z);

  //Note added: 10/08/13 pad() creates padding that is required to ensure 128Bytes are sent. May not be needed as new version of LV code maybe able to handle

  //Serial.print("START");
  //Send the data to the serial port
  Serial.print(F("DEL:"));              //Delta T
  Serial.print(dt, DEC);


  Serial.print(F(" # AX "));  //Accelerometer angle
  pad(accel_angle_x);
  //Serial.print(accel_angle_x, 2);
  Serial.print(F(" # AY "));
  pad(accel_angle_y);
  //Serial.print(accel_angle_y, 2);
  Serial.print(F(" # GX "));
  pad(gyro_x);
  //Serial.print(unfiltered_gyro_angle_x, 2);        //Gyroscope angle
  Serial.print(F(" # GY "));
  pad(gyro_y);
  //Serial.print(unfiltered_gyro_angle_y, 2);
  Serial.print(F(" # GZ "));
  pad(gyro_z);
  //Serial.print(unfiltered_gyro_angle_z, 2);

  Serial.print("\n");
  //Serial.println(F(""));
  Serial.flush();
  // Delay so we don't swamp the serial port
  delay(5); //so not to swamp the serial port

}


// --------------------------------------------------------
// MPU6050_read
//
// This is a common function to read multiple bytes 
// from an I2C device.
//
// It uses the boolean parameter for Wire.endTransMission()
// to be able to hold or release the I2C-bus. 
// This is implemented in Arduino 1.0.1.
//
// Only this function is used to read. 
// There is no function for a single byte.
//
int MPU6050_read(int start, uint8_t *buffer, int size)
{
  int i, n, error;

  Wire.beginTransmission(MPU6050_I2C_ADDRESS);
  n = Wire.write(start);
  if (n != 1)
    return (-10);

  n = Wire.endTransmission(false);    // hold the I2C-bus
  if (n != 0)
    return (n);

  // Third parameter is true: relase I2C-bus after data is read.
  Wire.requestFrom(MPU6050_I2C_ADDRESS, size, true);
  i = 0;
  while(Wire.available() && i<size)
  {
    buffer[i++]=Wire.read();
  }
  if ( i != size)
    return (-11);

  return (0);  // return : no error
}


// --------------------------------------------------------
// MPU6050_write
//
// This is a common function to write multiple bytes to an I2C device.
//
// If only a single register is written,
// use the function MPU_6050_write_reg().
//
// Parameters:
//   start : Start address, use a define for the register
//   pData : A pointer to the data to write.
//   size  : The number of bytes to write.
//
// If only a single register is written, a pointer
// to the data has to be used, and the size is
// a single byte:
//   int data = 0;        // the data to write
//   MPU6050_write (MPU6050_PWR_MGMT_1, &c, 1);
//
int MPU6050_write(int start, const uint8_t *pData, int size)
{
  int n, error;

  Wire.beginTransmission(MPU6050_I2C_ADDRESS);
  n = Wire.write(start);        // write the start address
  if (n != 1)
    return (-20);

  n = Wire.write(pData, size);  // write data bytes
  if (n != size)
    return (-21);

  error = Wire.endTransmission(true); // release the I2C-bus
  if (error != 0)
    return (error);

  return (0);         // return : no error
}

// --------------------------------------------------------
// MPU6050_write_reg
//
// An extra function to write a single register.
// It is just a wrapper around the MPU_6050_write()
// function, and it is only a convenient function
// to make it easier to write a single register.
//
int MPU6050_write_reg(int reg, uint8_t data)
{
  int error;

  error = MPU6050_write(reg, &data, 1);

  return (error);
}

//This function pads the printed value to take up 
//7 characters Example: **20.16

void pad(float PadVal){

  //Positve Value
  if (PadVal >= 0){          //For positive value
    if(PadVal < 10){        //For positive value less than 10
      Serial.print("   ");   //0-9 ***0-9.00
    }  
    else if (PadVal < 100){    //values less than 100
      Serial.print("  ");        //10-99 **10-99.00
    }

  }
  else if(PadVal <= 0){      //for negative values
    if(PadVal > -10){        //for negative value greater than -10 
      Serial.print("  ");     //-9 - 0 **-1 - -9.00
    }  
    else if (PadVal > -100){   //for negative values lesss than -99
      Serial.print(" ");          //*-99.00
    }
  }

  Serial.print(PadVal, 2);  //print the padded value
}

I’m not sure what to say re: the above. My GUESS is that you are reading the registers at the same time they are being updated. Ideally this couldn’t happen but …

I note you read the 6050 once per loop() and that happens about every 50 msec (20 Hz). That’s “slow” enough that the 6050 should be able to keep up but that doesn’t mean your timing might be (infrequently) “bad”. Then again have you confirmed you can read the aforementioned “WhoAmI” register correctly … all the time ?

No I havent get confiremed it

Could u plz suggest me a way to get confirm about reading “WhoAMI” resgister all the time?

Thank You :slight_smile:

Could any one please help me to understand below coding part in MPU6050.cpp file

void MPU6050::getMotion6(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz) {
    I2Cdev::readBytes(devAddr, MPU6050_RA_ACCEL_XOUT_H, 14, buffer);
    *ax = (((int16_t)buffer[0]) << 8) | buffer[1];
    *ay = (((int16_t)buffer[2]) << 8) | buffer[3];
    *az = (((int16_t)buffer[4]) << 8) | buffer[5];
    *gx = (((int16_t)buffer[8]) << 8) | buffer[9];
    *gy = (((int16_t)buffer[10]) << 8) | buffer[11];
    *gz = (((int16_t)buffer[12]) << 8) | buffer[13];
}

why we are shifting bits to the left twice?