gobot.io/x/gobot@v1.16.0/drivers/i2c/mpu6050_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"time"
     7  
     8  	"gobot.io/x/gobot"
     9  )
    10  
    11  const mpu6050Address = 0x68
    12  
    13  const MPU6050_RA_ACCEL_XOUT_H = 0x3B
    14  const MPU6050_RA_PWR_MGMT_1 = 0x6B
    15  const MPU6050_PWR1_CLKSEL_BIT = 2
    16  const MPU6050_PWR1_CLKSEL_LENGTH = 3
    17  const MPU6050_CLOCK_PLL_XGYRO = 0x01
    18  const MPU6050_GYRO_FS_250 = 0x00
    19  const MPU6050_RA_GYRO_CONFIG = 0x1B
    20  const MPU6050_GCONFIG_FS_SEL_LENGTH = 2
    21  const MPU6050_GCONFIG_FS_SEL_BIT = 4
    22  const MPU6050_RA_ACCEL_CONFIG = 0x1C
    23  const MPU6050_ACONFIG_AFS_SEL_BIT = 4
    24  const MPU6050_ACONFIG_AFS_SEL_LENGTH = 2
    25  const MPU6050_ACCEL_FS_2 = 0x00
    26  const MPU6050_PWR1_SLEEP_BIT = 6
    27  const MPU6050_PWR1_ENABLE_BIT = 0
    28  
    29  type ThreeDData struct {
    30  	X int16
    31  	Y int16
    32  	Z int16
    33  }
    34  
    35  // MPU6050Driver is a new Gobot Driver for an MPU6050 I2C Accelerometer/Gyroscope.
    36  type MPU6050Driver struct {
    37  	name       string
    38  	connector  Connector
    39  	connection Connection
    40  	Config
    41  	interval      time.Duration
    42  	Accelerometer ThreeDData
    43  	Gyroscope     ThreeDData
    44  	Temperature   int16
    45  	gobot.Eventer
    46  }
    47  
    48  // NewMPU6050Driver creates a new Gobot Driver for an MPU6050 I2C Accelerometer/Gyroscope.
    49  //
    50  // Params:
    51  //		conn Connector - the Adaptor to use with this Driver
    52  //
    53  // Optional params:
    54  //		i2c.WithBus(int):	bus to use with this driver
    55  //		i2c.WithAddress(int):	address to use with this driver
    56  //
    57  func NewMPU6050Driver(a Connector, options ...func(Config)) *MPU6050Driver {
    58  	m := &MPU6050Driver{
    59  		name:      gobot.DefaultName("MPU6050"),
    60  		connector: a,
    61  		Config:    NewConfig(),
    62  		Eventer:   gobot.NewEventer(),
    63  	}
    64  
    65  	for _, option := range options {
    66  		option(m)
    67  	}
    68  
    69  	// TODO: add commands to API
    70  	return m
    71  }
    72  
    73  // Name returns the name of the device.
    74  func (h *MPU6050Driver) Name() string { return h.name }
    75  
    76  // SetName sets the name of the device.
    77  func (h *MPU6050Driver) SetName(n string) { h.name = n }
    78  
    79  // Connection returns the connection for the device.
    80  func (h *MPU6050Driver) Connection() gobot.Connection { return h.connector.(gobot.Connection) }
    81  
    82  // Start writes initialization bytes to sensor
    83  func (h *MPU6050Driver) Start() (err error) {
    84  	if err := h.initialize(); err != nil {
    85  		return err
    86  	}
    87  
    88  	return
    89  }
    90  
    91  // Halt returns true if devices is halted successfully
    92  func (h *MPU6050Driver) Halt() (err error) { return }
    93  
    94  // GetData fetches the latest data from the MPU6050
    95  func (h *MPU6050Driver) GetData() (err error) {
    96  	if _, err = h.connection.Write([]byte{MPU6050_RA_ACCEL_XOUT_H}); err != nil {
    97  		return
    98  	}
    99  
   100  	data := make([]byte, 14)
   101  	_, err = h.connection.Read(data)
   102  	if err != nil {
   103  		return
   104  	}
   105  
   106  	buf := bytes.NewBuffer(data)
   107  	binary.Read(buf, binary.BigEndian, &h.Accelerometer)
   108  	binary.Read(buf, binary.BigEndian, &h.Temperature)
   109  	binary.Read(buf, binary.BigEndian, &h.Gyroscope)
   110  	h.convertToCelsius()
   111  	return
   112  }
   113  
   114  func (h *MPU6050Driver) initialize() (err error) {
   115  	bus := h.GetBusOrDefault(h.connector.GetDefaultBus())
   116  	address := h.GetAddressOrDefault(mpu6050Address)
   117  
   118  	h.connection, err = h.connector.GetConnection(address, bus)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	// setClockSource
   124  	if _, err = h.connection.Write([]byte{MPU6050_RA_PWR_MGMT_1,
   125  		MPU6050_PWR1_CLKSEL_BIT,
   126  		MPU6050_PWR1_CLKSEL_LENGTH,
   127  		MPU6050_CLOCK_PLL_XGYRO}); err != nil {
   128  		return
   129  	}
   130  
   131  	// setFullScaleGyroRange
   132  	if _, err = h.connection.Write([]byte{MPU6050_RA_GYRO_CONFIG,
   133  		MPU6050_GCONFIG_FS_SEL_BIT,
   134  		MPU6050_GCONFIG_FS_SEL_LENGTH,
   135  		MPU6050_GYRO_FS_250}); err != nil {
   136  		return
   137  	}
   138  
   139  	// setFullScaleAccelRange
   140  	if _, err = h.connection.Write([]byte{MPU6050_RA_ACCEL_CONFIG,
   141  		MPU6050_ACONFIG_AFS_SEL_BIT,
   142  		MPU6050_ACONFIG_AFS_SEL_LENGTH,
   143  		MPU6050_ACCEL_FS_2}); err != nil {
   144  		return
   145  	}
   146  
   147  	// setSleepEnabled
   148  	if _, err = h.connection.Write([]byte{MPU6050_RA_PWR_MGMT_1,
   149  		MPU6050_PWR1_ENABLE_BIT,
   150  		0}); err != nil {
   151  		return
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  // The temperature sensor is -40 to +85 degrees Celsius.
   158  // It is a signed integer.
   159  // According to the datasheet:
   160  //   340 per degrees Celsius, -512 at 35 degrees.
   161  // At 0 degrees: -512 - (340 * 35) = -12412
   162  func (h *MPU6050Driver) convertToCelsius() {
   163  	h.Temperature = (h.Temperature + 12412) / 340
   164  }