gobot.io/x/gobot/v2@v2.1.0/platforms/intel-iot/curie/imu_driver.go (about)

     1  package curie
     2  
     3  import (
     4  	"errors"
     5  
     6  	"gobot.io/x/gobot/v2"
     7  	"gobot.io/x/gobot/v2/platforms/firmata"
     8  )
     9  
    10  const (
    11  	CURIE_IMU              = 0x11
    12  	CURIE_IMU_READ_ACCEL   = 0x00
    13  	CURIE_IMU_READ_GYRO    = 0x01
    14  	CURIE_IMU_READ_TEMP    = 0x02
    15  	CURIE_IMU_SHOCK_DETECT = 0x03
    16  	CURIE_IMU_STEP_COUNTER = 0x04
    17  	CURIE_IMU_TAP_DETECT   = 0x05
    18  	CURIE_IMU_READ_MOTION  = 0x06
    19  )
    20  
    21  // AccelerometerData is what gets returned with the "Accelerometer" event.
    22  type AccelerometerData struct {
    23  	X int16
    24  	Y int16
    25  	Z int16
    26  }
    27  
    28  // GyroscopeData is what gets returned with the "Gyroscope" event.
    29  type GyroscopeData struct {
    30  	X int16
    31  	Y int16
    32  	Z int16
    33  }
    34  
    35  // ShockData is what gets returned with the "Shock" event.
    36  type ShockData struct {
    37  	Axis      byte
    38  	Direction byte
    39  }
    40  
    41  // TapData is what gets returned with the "Tap" event.
    42  type TapData struct {
    43  	Axis      byte
    44  	Direction byte
    45  }
    46  
    47  // MotionData is what gets returned with the "Motion" event.
    48  type MotionData struct {
    49  	AX int16
    50  	AY int16
    51  	AZ int16
    52  	GX int16
    53  	GY int16
    54  	GZ int16
    55  }
    56  
    57  // IMUDriver represents the IMU that is built-in to the Curie
    58  type IMUDriver struct {
    59  	name       string
    60  	connection *firmata.Adaptor
    61  	gobot.Eventer
    62  }
    63  
    64  // NewIMUDriver returns a new IMUDriver
    65  func NewIMUDriver(a *firmata.Adaptor) *IMUDriver {
    66  	imu := &IMUDriver{
    67  		name:       gobot.DefaultName("CurieIMU"),
    68  		connection: a,
    69  		Eventer:    gobot.NewEventer(),
    70  	}
    71  
    72  	return imu
    73  }
    74  
    75  // Start starts up the IMUDriver
    76  func (imu *IMUDriver) Start() (err error) {
    77  	imu.connection.On("SysexResponse", func(res interface{}) {
    78  		data := res.([]byte)
    79  		imu.handleEvent(data)
    80  	})
    81  	return
    82  }
    83  
    84  // Halt stops the IMUDriver
    85  func (imu *IMUDriver) Halt() (err error) {
    86  	return
    87  }
    88  
    89  // Name returns the IMUDriver's name
    90  func (imu *IMUDriver) Name() string { return imu.name }
    91  
    92  // SetName sets the IMUDriver'ss name
    93  func (imu *IMUDriver) SetName(n string) { imu.name = n }
    94  
    95  // Connection returns the IMUDriver's Connection
    96  func (imu *IMUDriver) Connection() gobot.Connection { return imu.connection }
    97  
    98  // ReadAccelerometer calls the Curie's built-in accelerometer. The result will
    99  // be returned by the Sysex response message
   100  func (imu *IMUDriver) ReadAccelerometer() error {
   101  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_ACCEL})
   102  }
   103  
   104  // ReadGyroscope calls the Curie's built-in gyroscope. The result will
   105  // be returned by the Sysex response message
   106  func (imu *IMUDriver) ReadGyroscope() error {
   107  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_GYRO})
   108  }
   109  
   110  // ReadTemperature calls the Curie's built-in temperature sensor.
   111  // The result will be returned by the Sysex response message
   112  func (imu *IMUDriver) ReadTemperature() error {
   113  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_TEMP})
   114  }
   115  
   116  // EnableShockDetection turns on/off the Curie's built-in shock detection.
   117  // The result will be returned by the Sysex response message
   118  func (imu *IMUDriver) EnableShockDetection(detect bool) error {
   119  	var d byte
   120  	if detect {
   121  		d = 1
   122  	}
   123  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_SHOCK_DETECT, d})
   124  }
   125  
   126  // EnableStepCounter turns on/off the Curie's built-in step counter.
   127  // The result will be returned by the Sysex response message
   128  func (imu *IMUDriver) EnableStepCounter(count bool) error {
   129  	var c byte
   130  	if count {
   131  		c = 1
   132  	}
   133  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_STEP_COUNTER, c})
   134  }
   135  
   136  // EnableTapDetection turns on/off the Curie's built-in tap detection.
   137  // The result will be returned by the Sysex response message
   138  func (imu *IMUDriver) EnableTapDetection(detect bool) error {
   139  	var d byte
   140  	if detect {
   141  		d = 1
   142  	}
   143  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_TAP_DETECT, d})
   144  }
   145  
   146  // ReadMotion calls the Curie's built-in accelerometer & gyroscope.
   147  // The result will be returned by the Sysex response message
   148  func (imu *IMUDriver) ReadMotion() error {
   149  	return imu.connection.WriteSysex([]byte{CURIE_IMU, CURIE_IMU_READ_MOTION})
   150  }
   151  
   152  func (imu *IMUDriver) handleEvent(data []byte) (err error) {
   153  	if data[1] == CURIE_IMU {
   154  		switch data[2] {
   155  		case CURIE_IMU_READ_ACCEL:
   156  			val, err := parseAccelerometerData(data)
   157  			if err == nil {
   158  				imu.Publish("Accelerometer", val)
   159  			}
   160  		case CURIE_IMU_READ_GYRO:
   161  			val, err := parseGyroscopeData(data)
   162  			if err == nil {
   163  				imu.Publish("Gyroscope", val)
   164  			}
   165  		case CURIE_IMU_READ_TEMP:
   166  			val, err := parseTemperatureData(data)
   167  			if err == nil {
   168  				imu.Publish("Temperature", val)
   169  			}
   170  		case CURIE_IMU_SHOCK_DETECT:
   171  			val, err := parseShockData(data)
   172  			if err == nil {
   173  				imu.Publish("Shock", val)
   174  			}
   175  		case CURIE_IMU_STEP_COUNTER:
   176  			val, err := parseStepData(data)
   177  			if err == nil {
   178  				imu.Publish("Steps", val)
   179  			}
   180  		case CURIE_IMU_TAP_DETECT:
   181  			val, err := parseTapData(data)
   182  			if err == nil {
   183  				imu.Publish("Tap", val)
   184  			}
   185  		case CURIE_IMU_READ_MOTION:
   186  			val, err := parseMotionData(data)
   187  			if err == nil {
   188  				imu.Publish("Motion", val)
   189  			}
   190  		}
   191  	}
   192  	return
   193  }
   194  
   195  func parseAccelerometerData(data []byte) (*AccelerometerData, error) {
   196  	if len(data) < 9 {
   197  		return nil, errors.New("Invalid data")
   198  	}
   199  	x := int16(uint16(data[3]) | uint16(data[4])<<7)
   200  	y := int16(uint16(data[5]) | uint16(data[6])<<7)
   201  	z := int16(uint16(data[7]) | uint16(data[8])<<7)
   202  
   203  	res := &AccelerometerData{X: x, Y: y, Z: z}
   204  	return res, nil
   205  }
   206  
   207  func parseGyroscopeData(data []byte) (*GyroscopeData, error) {
   208  	if len(data) < 9 {
   209  		return nil, errors.New("Invalid data")
   210  	}
   211  	x := int16(uint16(data[3]) | uint16(data[4])<<7)
   212  	y := int16(uint16(data[5]) | uint16(data[6])<<7)
   213  	z := int16(uint16(data[7]) | uint16(data[8])<<7)
   214  
   215  	res := &GyroscopeData{X: x, Y: y, Z: z}
   216  	return res, nil
   217  }
   218  
   219  func parseTemperatureData(data []byte) (float32, error) {
   220  	if len(data) < 8 {
   221  		return 0, errors.New("Invalid data")
   222  	}
   223  	t1 := int16(uint16(data[3]) | uint16(data[4])<<7)
   224  	t2 := int16(uint16(data[5]) | uint16(data[6])<<7)
   225  
   226  	res := (float32(t1+(t2*8)) / 512.0) + 23.0
   227  	return res, nil
   228  }
   229  
   230  func parseShockData(data []byte) (*ShockData, error) {
   231  	if len(data) < 6 {
   232  		return nil, errors.New("Invalid data")
   233  	}
   234  
   235  	res := &ShockData{Axis: data[3], Direction: data[4]}
   236  	return res, nil
   237  }
   238  
   239  func parseStepData(data []byte) (int16, error) {
   240  	if len(data) < 6 {
   241  		return 0, errors.New("Invalid data")
   242  	}
   243  
   244  	res := int16(uint16(data[3]) | uint16(data[4])<<7)
   245  	return res, nil
   246  }
   247  
   248  func parseTapData(data []byte) (*TapData, error) {
   249  	if len(data) < 6 {
   250  		return nil, errors.New("Invalid data")
   251  	}
   252  
   253  	res := &TapData{Axis: data[3], Direction: data[4]}
   254  	return res, nil
   255  }
   256  
   257  func parseMotionData(data []byte) (*MotionData, error) {
   258  	if len(data) < 16 {
   259  		return nil, errors.New("Invalid data")
   260  	}
   261  	ax := int16(uint16(data[3]) | uint16(data[4])<<7)
   262  	ay := int16(uint16(data[5]) | uint16(data[6])<<7)
   263  	az := int16(uint16(data[7]) | uint16(data[8])<<7)
   264  
   265  	gx := int16(uint16(data[9]) | uint16(data[10])<<7)
   266  	gy := int16(uint16(data[11]) | uint16(data[12])<<7)
   267  	gz := int16(uint16(data[13]) | uint16(data[14])<<7)
   268  
   269  	res := &MotionData{AX: ax, AY: ay, AZ: az, GX: gx, GY: gy, GZ: gz}
   270  	return res, nil
   271  }