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 }