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  }