224 lines
4.5 KiB
Go
224 lines
4.5 KiB
Go
package mpu6050
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"golang.org/x/exp/io/i2c"
|
|
)
|
|
|
|
const (
|
|
mpuAddr = 0x68
|
|
|
|
// MPU registers
|
|
|
|
// Power management
|
|
// powerMgmt1 = 0x6B
|
|
// powerMgmt2 = 0x6C
|
|
// Acceleration
|
|
accelXOut0 = 0x3B
|
|
accelYOut0 = 0x3D
|
|
accelZOut0 = 0x3F
|
|
// Temperature
|
|
tempOut0 = 0x41
|
|
|
|
// Gyro
|
|
gyroXOut0 = 0x43
|
|
gyroYOut0 = 0x45
|
|
gyroZOut0 = 0x47
|
|
// Configs
|
|
accelConfig = 0x1C
|
|
gyroConfig = 0x1B
|
|
mpuConfig = 0x1A
|
|
|
|
gravityMS2 = 9.80665
|
|
|
|
// Scale modifiers
|
|
AccelScaleModifier2G = 16384.0
|
|
AccelScaleModifier4G = 8192.0
|
|
AccelScaleModifier8G = 4096.0
|
|
AccelScaleModifier16G = 2048.0
|
|
|
|
GyroScaleModifier250DEG = 131.0
|
|
GyroScaleModifier500DEG = 65.5
|
|
GyroScaleModifier1000DEG = 32.8
|
|
GyroScaleModifier2000DEG = 16.4
|
|
|
|
// Accel range
|
|
AccelRange2G = 0x00
|
|
AccelRange4G = 0x08
|
|
AccelRange8G = 0x10
|
|
AccelRange16G = 0x18
|
|
|
|
GyroRange250DEG = 0x00
|
|
GyroRange500DEG = 0x08
|
|
GyroRange1000DEG = 0x10
|
|
GyroRange2000DEG = 0x18
|
|
|
|
FilterBw256 = 0x00
|
|
FilterBw188 = 0x01
|
|
FilterBw98 = 0x02
|
|
FilterBw42 = 0x03
|
|
FilterBw20 = 0x04
|
|
FilterBw10 = 0x05
|
|
FilterBw5 = 0x06
|
|
)
|
|
|
|
type device struct {
|
|
device *i2c.Device
|
|
}
|
|
|
|
type Device interface {
|
|
GetTemp() (float32, error)
|
|
|
|
SetAccelRange(r byte) error
|
|
GetAccel(inG bool) ([3]float32, error)
|
|
|
|
SetGyroRange(r byte) error
|
|
GetGyro() ([3]float32, error)
|
|
|
|
io.Closer
|
|
}
|
|
|
|
func Open() (Device, error) {
|
|
d, err := i2c.Open(&i2c.Devfs{Dev: "/dev/i2c-1"}, mpuAddr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open i2c: %w", err)
|
|
}
|
|
return &device{
|
|
device: d,
|
|
}, nil
|
|
}
|
|
|
|
func (d *device) GetTemp() (float32, error) {
|
|
rawTemp, err := d.readWord(tempOut0)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return (float32(rawTemp) / 340.0) + 36.53, nil
|
|
}
|
|
|
|
func (d *device) SetAccelRange(accelRange byte) error {
|
|
if err := d.device.WriteReg(accelConfig, []byte{0}); err != nil {
|
|
return err
|
|
}
|
|
if err := d.device.WriteReg(accelConfig, []byte{accelRange}); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *device) readAccelRange() (byte, error) {
|
|
rawData := make([]byte, 1)
|
|
if err := d.device.ReadReg(accelConfig, rawData); err != nil {
|
|
return 0, err
|
|
}
|
|
return rawData[0], nil
|
|
}
|
|
|
|
func (d *device) GetAccel(inG bool) ([3]float32, error) {
|
|
x, err := d.readWord(accelXOut0)
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read x: %w", err)
|
|
}
|
|
y, err := d.readWord(accelYOut0)
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read y: %w", err)
|
|
}
|
|
z, err := d.readWord(accelZOut0)
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read z: %w", err)
|
|
}
|
|
|
|
scale := float32(AccelScaleModifier2G)
|
|
accelRange, err := d.readAccelRange()
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read accel range: %w", err)
|
|
}
|
|
switch accelRange {
|
|
case AccelRange2G:
|
|
scale = AccelScaleModifier2G
|
|
case AccelRange4G:
|
|
scale = AccelScaleModifier2G
|
|
case AccelRange8G:
|
|
scale = AccelScaleModifier2G
|
|
case AccelRange16G:
|
|
scale = AccelScaleModifier2G
|
|
//default:
|
|
// log.Println("not foudn accel range:", accelRange)
|
|
}
|
|
scale = 1 / scale
|
|
|
|
if !inG {
|
|
scale /= gravityMS2
|
|
}
|
|
return [3]float32{
|
|
float32(x) * scale,
|
|
float32(y) * scale,
|
|
float32(z) * scale,
|
|
}, nil
|
|
}
|
|
|
|
func (d *device) SetGyroRange(gyroRange byte) error {
|
|
if err := d.device.WriteReg(gyroConfig, []byte{0}); err != nil {
|
|
return err
|
|
}
|
|
if err := d.device.WriteReg(gyroConfig, []byte{gyroRange}); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *device) readGyroRange() (byte, error) {
|
|
rawData := make([]byte, 1)
|
|
if err := d.device.ReadReg(gyroConfig, rawData); err != nil {
|
|
return 0, err
|
|
}
|
|
return rawData[0], nil
|
|
}
|
|
|
|
func (d *device) GetGyro() ([3]float32, error) {
|
|
x, err := d.readWord(gyroXOut0)
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read x: %w", err)
|
|
}
|
|
y, err := d.readWord(gyroYOut0)
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read y: %w", err)
|
|
}
|
|
z, err := d.readWord(gyroZOut0)
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read z: %w", err)
|
|
}
|
|
|
|
scale := float32(GyroScaleModifier250DEG)
|
|
gyroRange, err := d.readGyroRange()
|
|
if err != nil {
|
|
return [3]float32{}, fmt.Errorf("read gyro range: %w", err)
|
|
}
|
|
switch gyroRange {
|
|
case GyroRange250DEG:
|
|
scale = GyroScaleModifier250DEG
|
|
case GyroRange500DEG:
|
|
scale = GyroScaleModifier500DEG
|
|
case GyroRange1000DEG:
|
|
scale = GyroScaleModifier1000DEG
|
|
case GyroRange2000DEG:
|
|
scale = GyroScaleModifier2000DEG
|
|
// default:
|
|
// log.Println("not found gyro range:", gyroRange)
|
|
}
|
|
return [3]float32{
|
|
float32(x) / scale,
|
|
float32(y) / scale,
|
|
float32(z) / scale,
|
|
}, nil
|
|
}
|
|
|
|
func (d *device) Close() error {
|
|
defer func() {
|
|
d.device = nil
|
|
}()
|
|
return d.device.Close()
|
|
}
|