gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/mpu6050_driver_test.go (about) 1 package i2c 2 3 import ( 4 "errors" 5 "strings" 6 "testing" 7 8 "gobot.io/x/gobot/v2" 9 "gobot.io/x/gobot/v2/gobottest" 10 ) 11 12 // this ensures that the implementation is based on i2c.Driver, which implements the gobot.Driver 13 // and tests all implementations, so no further tests needed here for gobot.Driver interface 14 var _ gobot.Driver = (*MPU6050Driver)(nil) 15 16 func initTestMPU6050WithStubbedAdaptor() (*MPU6050Driver, *i2cTestAdaptor) { 17 a := newI2cTestAdaptor() 18 d := NewMPU6050Driver(a) 19 if err := d.Start(); err != nil { 20 panic(err) 21 } 22 return d, a 23 } 24 25 func TestNewMPU6050Driver(t *testing.T) { 26 var di interface{} = NewMPU6050Driver(newI2cTestAdaptor()) 27 d, ok := di.(*MPU6050Driver) 28 if !ok { 29 t.Errorf("NewMPU6050Driver() should have returned a *MPU6050Driver") 30 } 31 gobottest.Refute(t, d.Driver, nil) 32 gobottest.Assert(t, strings.HasPrefix(d.name, "MPU6050"), true) 33 gobottest.Assert(t, d.defaultAddress, 0x68) 34 gobottest.Assert(t, d.dlpf, MPU6050DlpfConfig(0x00)) 35 gobottest.Assert(t, d.frameSync, MPU6050FrameSyncConfig(0x00)) 36 gobottest.Assert(t, d.accelFs, MPU6050AccelFsConfig(0x00)) 37 gobottest.Assert(t, d.gyroFs, MPU6050GyroFsConfig(0x00)) 38 gobottest.Assert(t, d.clock, MPU6050Pwr1ClockConfig(0x01)) 39 gobottest.Assert(t, d.gravity, 9.80665) 40 } 41 42 func TestMPU6050Options(t *testing.T) { 43 // This is a general test, that options are applied in constructor by using the common WithBus() option and 44 // least one of this driver. Further tests for options can also be done by call of "WithOption(val)(d)". 45 d := NewMPU6050Driver(newI2cTestAdaptor(), WithBus(2), WithMPU6050DigitalFilter(0x06)) 46 gobottest.Assert(t, d.GetBusOrDefault(1), 2) 47 gobottest.Assert(t, d.dlpf, MPU6050DlpfConfig(0x06)) 48 } 49 50 func TestWithMPU6050FrameSync(t *testing.T) { 51 d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050FrameSync(0x07)) 52 gobottest.Assert(t, d.frameSync, MPU6050FrameSyncConfig(0x07)) 53 } 54 55 func TestWithMPU6050AccelFullScaleRange(t *testing.T) { 56 d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050AccelFullScaleRange(0x02)) 57 gobottest.Assert(t, d.accelFs, MPU6050AccelFsConfig(0x02)) 58 } 59 60 func TestWithMPU6050GyroFullScaleRange(t *testing.T) { 61 d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050GyroFullScaleRange(0x03)) 62 gobottest.Assert(t, d.gyroFs, MPU6050GyroFsConfig(0x03)) 63 } 64 65 func TestWithMPU6050ClockSource(t *testing.T) { 66 d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050ClockSource(0x05)) 67 gobottest.Assert(t, d.clock, MPU6050Pwr1ClockConfig(0x05)) 68 } 69 70 func TestWithMPU6050Gravity(t *testing.T) { 71 d := NewMPU6050Driver(newI2cTestAdaptor(), WithMPU6050Gravity(1.0)) 72 gobottest.Assert(t, d.gravity, 1.0) 73 } 74 75 func TestMPU6050GetData(t *testing.T) { 76 // sequence to read values 77 // * reset device and prepare config registers, see test for Start() 78 // * write first data register address (0x3B) 79 // * read 3 x 2 bytes acceleration.X, Y, Z data, little-endian (MSB, LSB) 80 // * read 2 bytes temperature data, little-endian (MSB, LSB) 81 // * read 3 x 2 bytes gyroscope.X, Y, Z data, little-endian (MSB, LSB) 82 // * scale 83 // Acceleration: raw value / gain * standard gravity [m/s²] 84 // Temperature: raw value / 340 + 36.53 [°C] 85 // Gyroscope: raw value / gain [°/s] 86 87 // arrange 88 d, adaptor := initTestMPU6050WithStubbedAdaptor() 89 d.Start() 90 91 accData := []byte{0x00, 0x01, 0x02, 0x04, 0x08, 0x16} 92 tempData := []byte{0x32, 0x64} 93 gyroData := []byte{0x16, 0x08, 0x04, 0x02, 0x01, 0x00} 94 95 wantAccel := MPU6050ThreeDData{ 96 X: 0x0001 / 16384.0 * d.gravity, 97 Y: 0x0204 / 16384.0 * d.gravity, 98 Z: 0x0816 / 16384.0 * d.gravity, 99 } 100 wantGyro := MPU6050ThreeDData{ 101 X: 0x1608 / 131.0, 102 Y: 0x0402 / 131.0, 103 Z: 0x0100 / 131.0, 104 } 105 wantTemp := float64(0x3264)/340 + 36.53 106 107 adaptor.i2cReadImpl = func(b []byte) (int, error) { 108 copy(b, append(append(accData, tempData...), gyroData...)) 109 return len(b), nil 110 } 111 // act 112 d.GetData() 113 // assert 114 gobottest.Assert(t, d.Accelerometer, wantAccel) 115 gobottest.Assert(t, d.Gyroscope, wantGyro) 116 gobottest.Assert(t, d.Temperature, wantTemp) 117 } 118 119 func TestMPU6050GetDataReadError(t *testing.T) { 120 d, adaptor := initTestMPU6050WithStubbedAdaptor() 121 d.Start() 122 123 adaptor.i2cReadImpl = func(b []byte) (int, error) { 124 return 0, errors.New("read error") 125 } 126 127 gobottest.Assert(t, d.GetData(), errors.New("read error")) 128 } 129 130 func TestMPU6050GetDataWriteError(t *testing.T) { 131 d, adaptor := initTestMPU6050WithStubbedAdaptor() 132 d.Start() 133 134 adaptor.i2cWriteImpl = func(b []byte) (int, error) { 135 return 0, errors.New("write error") 136 } 137 138 gobottest.Assert(t, d.GetData(), errors.New("write error")) 139 } 140 141 func TestMPU6050_initialize(t *testing.T) { 142 // sequence for initialization the device on Start() 143 // reset (according to data sheet) 144 // * write power management 1 register address (0x6B) 145 // * set device reset bit - write 0x80 146 // * read device reset bit until it becomes false (timeout 100 ms) 147 // * write power management 1 register address (0x6B) 148 // * read value 149 // * wait some time before retry 150 // * write signal path reset register address (0x68) 151 // * reset all sensors - write 0x07 152 // * wait 100 ms 153 // config 154 // * write general config register address (0x1A) 155 // * disable external sync and set filter bandwidth to 260 HZ - write 0x00 156 // * write gyroscope config register address (0x1B) 157 // * set full scale to 250 °/s - write 0x00 158 // * write accelerometer config register address (0x1C) 159 // * set full scale to 2 g - write 0x00 160 // * write power management 1 register address (0x6B) 161 // * set clock source to PLL with X and switch off sleep bit - write 0x01 162 // arrange 163 a := newI2cTestAdaptor() 164 d := NewMPU6050Driver(a) 165 readCallCounter := 0 166 a.i2cReadImpl = func(b []byte) (int, error) { 167 readCallCounter++ 168 // emulate ready 169 b[0] = 0x00 170 return len(b), nil 171 } 172 // act, assert - initialize() must be called on Start() 173 err := d.Start() 174 // assert 175 gobottest.Assert(t, err, nil) 176 gobottest.Assert(t, readCallCounter, 1) 177 gobottest.Assert(t, len(a.written), 13) 178 gobottest.Assert(t, a.written[0], uint8(0x6B)) 179 gobottest.Assert(t, a.written[1], uint8(0x80)) 180 gobottest.Assert(t, a.written[2], uint8(0x6B)) 181 gobottest.Assert(t, a.written[3], uint8(0x68)) 182 gobottest.Assert(t, a.written[4], uint8(0x07)) 183 gobottest.Assert(t, a.written[5], uint8(0x1A)) 184 gobottest.Assert(t, a.written[6], uint8(0x00)) 185 gobottest.Assert(t, a.written[7], uint8(0x1B)) 186 gobottest.Assert(t, a.written[8], uint8(0x00)) 187 gobottest.Assert(t, a.written[9], uint8(0x1C)) 188 gobottest.Assert(t, a.written[10], uint8(0x00)) 189 gobottest.Assert(t, a.written[11], uint8(0x6B)) 190 gobottest.Assert(t, a.written[12], uint8(0x01)) 191 }