tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/mpu6050/mpu6050.go (about) 1 // Package mpu6050 provides a driver for the MPU6050 accelerometer and gyroscope 2 // made by InvenSense. 3 // 4 // Datasheets: 5 // https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf 6 // https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf 7 package mpu6050 // import "tinygo.org/x/drivers/mpu6050" 8 9 import ( 10 "tinygo.org/x/drivers" 11 "tinygo.org/x/drivers/internal/legacy" 12 ) 13 14 // Device wraps an I2C connection to a MPU6050 device. 15 type Device struct { 16 bus drivers.I2C 17 Address uint16 18 } 19 20 // New creates a new MPU6050 connection. The I2C bus must already be 21 // configured. 22 // 23 // This function only creates the Device object, it does not touch the device. 24 func New(bus drivers.I2C) Device { 25 return Device{bus, Address} 26 } 27 28 // Connected returns whether a MPU6050 has been found. 29 // It does a "who am I" request and checks the response. 30 func (d Device) Connected() bool { 31 data := []byte{0} 32 legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data) 33 return data[0] == 0x68 34 } 35 36 // Configure sets up the device for communication. 37 func (d Device) Configure() error { 38 return d.SetClockSource(CLOCK_INTERNAL) 39 } 40 41 // ReadAcceleration reads the current acceleration from the device and returns 42 // it in µg (micro-gravity). When one of the axes is pointing straight to Earth 43 // and the sensor is not moving the returned value will be around 1000000 or 44 // -1000000. 45 func (d Device) ReadAcceleration() (x int32, y int32, z int32) { 46 data := make([]byte, 6) 47 legacy.ReadRegister(d.bus, uint8(d.Address), ACCEL_XOUT_H, data) 48 // Now do two things: 49 // 1. merge the two values to a 16-bit number (and cast to a 32-bit integer) 50 // 2. scale the value to bring it in the -1000000..1000000 range. 51 // This is done with a trick. What we do here is essentially multiply by 52 // 1000000 and divide by 16384 to get the original scale, but to avoid 53 // overflow we do it at 1/64 of the value: 54 // 1000000 / 64 = 15625 55 // 16384 / 64 = 256 56 x = int32(int16((uint16(data[0])<<8)|uint16(data[1]))) * 15625 / 256 57 y = int32(int16((uint16(data[2])<<8)|uint16(data[3]))) * 15625 / 256 58 z = int32(int16((uint16(data[4])<<8)|uint16(data[5]))) * 15625 / 256 59 return 60 } 61 62 // ReadRotation reads the current rotation from the device and returns it in 63 // µ°/s (micro-degrees/sec). This means that if you were to do a complete 64 // rotation along one axis and while doing so integrate all values over time, 65 // you would get a value close to 360000000. 66 func (d Device) ReadRotation() (x int32, y int32, z int32) { 67 data := make([]byte, 6) 68 legacy.ReadRegister(d.bus, uint8(d.Address), GYRO_XOUT_H, data) 69 // First the value is converted from a pair of bytes to a signed 16-bit 70 // value and then to a signed 32-bit value to avoid integer overflow. 71 // Then the value is scaled to µ°/s (micro-degrees per second). 72 // This is done in the following steps: 73 // 1. Multiply by 250 * 1000_000 74 // 2. Divide by 32768 75 // The following calculation (x * 15625 / 2048 * 1000) is essentially the 76 // same but avoids overflow. First both operations are divided by 16 leading 77 // to multiply by 15625000 and divide by 2048, and then part of the multiply 78 // is done after the divide instead of before. 79 x = int32(int16((uint16(data[0])<<8)|uint16(data[1]))) * 15625 / 2048 * 1000 80 y = int32(int16((uint16(data[2])<<8)|uint16(data[3]))) * 15625 / 2048 * 1000 81 z = int32(int16((uint16(data[4])<<8)|uint16(data[5]))) * 15625 / 2048 * 1000 82 return 83 } 84 85 // SetClockSource allows the user to configure the clock source. 86 func (d Device) SetClockSource(source uint8) error { 87 return legacy.WriteRegister(d.bus, uint8(d.Address), PWR_MGMT_1, []uint8{source}) 88 } 89 90 // SetFullScaleGyroRange allows the user to configure the scale range for the gyroscope. 91 func (d Device) SetFullScaleGyroRange(rng uint8) error { 92 return legacy.WriteRegister(d.bus, uint8(d.Address), GYRO_CONFIG, []uint8{rng}) 93 } 94 95 // SetFullScaleAccelRange allows the user to configure the scale range for the accelerometer. 96 func (d Device) SetFullScaleAccelRange(rng uint8) error { 97 return legacy.WriteRegister(d.bus, uint8(d.Address), ACCEL_CONFIG, []uint8{rng}) 98 }