Remove unecessary if satements in getHeading() and add getRawHeading()
[3501/2017steamworks] / src / org / usfirst / frc / team3501 / robot / utils / BNO055.java
CommitLineData
00ae4fb3
ES
1package org.usfirst.frc.team3501.robot.utils;
2
3import java.util.TimerTask;
4
5import edu.wpi.first.wpilibj.I2C;
6import edu.wpi.first.wpilibj.Timer;
7
8/**
9 * BNO055 IMU for the FIRST Robotics Competition.
10 * References throughout the code are to the following sensor documentation:
11 * http://git.io/vuOl1
12 *
13 * To use the sensor, wire up to it over I2C on the roboRIO.
14 * Creating an instance of this class will cause communications with the sensor
15 * to being.All communications with the sensor occur in a separate thread
16 * from your robot code to avoid blocking the main robot program execution.
17 *
18 * Example:
19 * private static BNO055 imu;
20 *
21 * public Robot() {
22 * imu = BNO055.getInstance(BNO055.opmode_t.OPERATION_MODE_IMUPLUS,
23 * BNO055.vector_type_t.VECTOR_EULER);
24 * }
25 *
26 * You can check the status of the sensor by using the following methods:
27 * isSensorPresent(); //Checks if the code can talk to the sensor over I2C
28 * // If this returns false, check your wiring.
29 * isInitialized(); //Checks if the sensor initialization has completed.
30 * // Initialization takes about 3 seconds. You won't get
31 * // position data back from the sensor until its init'd.
32 * isCalibrated(); //The BNO055 will return position data after its init'd,
33 * // but the position data may be inaccurate until all
34 * // required sensors report they are calibrated. Some
35 * // Calibration sequences require you to move the BNO055
36 * // around. See the method comments for more info.
37 *
38 * Once the sensor calibration is complete , you can get position data by
39 * by using the getVector() method. See this method definiton for usage info.
40 *
41 * This code was originally ported from arduino source developed by Adafruit.
42 * See the original comment header below.
43 *
44 * @author james@team2168.org
45 *
46 *
47 * ORIGINAL ADAFRUIT HEADER -
48 * https://github.com/adafruit/Adafruit_BNO055/
49 * =======================================================================
50 * This is a library for the BNO055 orientation sensor
51 *
52 * Designed specifically to work with the Adafruit BNO055 Breakout.
53 *
54 * Pick one up today in the adafruit shop!
55 * ------> http://www.adafruit.com/products
56 *
57 * These sensors use I2C to communicate, 2 pins are required to
58 * interface.
59 *
60 * Adafruit invests time and resources providing this open source code,
61 * please support Adafruit and open-source hardware by purchasing
62 * products
63 * from Adafruit!
64 *
65 * Written by KTOWN for Adafruit Industries.
66 *
67 * MIT license, all text above must be included in any redistribution
68 *
69 */
70public class BNO055 {
71 // Tread variables
72 private java.util.Timer executor;
73 private static final long THREAD_PERIOD = 20; // ms - max poll rate on sensor.
74
75 public static final byte BNO055_ADDRESS_A = 0x28;
76 public static final byte BNO055_ADDRESS_B = 0x29;
77 public static final int BNO055_ID = 0xA0;
78
79 private static BNO055 instance;
80
81 private static I2C imu;
82 private static int _mode;
83 private static opmode_t requestedMode; // user requested mode of operation.
84 private static vector_type_t requestedVectorType;
85
86 // State machine variables
87 private volatile int state = 0;
88 private volatile boolean sensorPresent = false;
89 private volatile boolean initialized = false;
90 private volatile double currentTime; // seconds
91 private volatile double nextTime; // seconds
92 private volatile byte[] positionVector = new byte[6];
93 private volatile long turns = 0;
94 private volatile double[] xyz = new double[3];
95
f7a207f1 96 private double zeroReferenceConst = 0;
00ae4fb3
ES
97
98 public class SystemStatus {
99 public int system_status;
100 public int self_test_result;
101 public int system_error;
102 }
103
104 public enum reg_t {
105 /* Page id register definition */
106 BNO055_PAGE_ID_ADDR(0X07),
107
108 /* PAGE0 REGISTER DEFINITION START */
109 BNO055_CHIP_ID_ADDR(0x00), BNO055_ACCEL_REV_ID_ADDR(
110 0x01), BNO055_MAG_REV_ID_ADDR(0x02), BNO055_GYRO_REV_ID_ADDR(
111 0x03), BNO055_SW_REV_ID_LSB_ADDR(0x04), BNO055_SW_REV_ID_MSB_ADDR(
112 0x05), BNO055_BL_REV_ID_ADDR(0X06),
113
114 /* Accel data register */
115 BNO055_ACCEL_DATA_X_LSB_ADDR(0X08), BNO055_ACCEL_DATA_X_MSB_ADDR(
116 0X09), BNO055_ACCEL_DATA_Y_LSB_ADDR(0X0A), BNO055_ACCEL_DATA_Y_MSB_ADDR(
117 0X0B), BNO055_ACCEL_DATA_Z_LSB_ADDR(
118 0X0C), BNO055_ACCEL_DATA_Z_MSB_ADDR(0X0D),
119
120 /* Mag data register */
121 BNO055_MAG_DATA_X_LSB_ADDR(0X0E), BNO055_MAG_DATA_X_MSB_ADDR(
122 0X0F), BNO055_MAG_DATA_Y_LSB_ADDR(0X10), BNO055_MAG_DATA_Y_MSB_ADDR(
123 0X11), BNO055_MAG_DATA_Z_LSB_ADDR(
124 0X12), BNO055_MAG_DATA_Z_MSB_ADDR(0X13),
125
126 /* Gyro data registers */
127 BNO055_GYRO_DATA_X_LSB_ADDR(0X14), BNO055_GYRO_DATA_X_MSB_ADDR(
128 0X15), BNO055_GYRO_DATA_Y_LSB_ADDR(0X16), BNO055_GYRO_DATA_Y_MSB_ADDR(
129 0X17), BNO055_GYRO_DATA_Z_LSB_ADDR(
130 0X18), BNO055_GYRO_DATA_Z_MSB_ADDR(0X19),
131
132 /* Euler data registers */
133 BNO055_EULER_H_LSB_ADDR(0X1A), BNO055_EULER_H_MSB_ADDR(
134 0X1B), BNO055_EULER_R_LSB_ADDR(0X1C), BNO055_EULER_R_MSB_ADDR(
135 0X1D), BNO055_EULER_P_LSB_ADDR(0X1E), BNO055_EULER_P_MSB_ADDR(0X1F),
136
137 /* Quaternion data registers */
138 BNO055_QUATERNION_DATA_W_LSB_ADDR(0X20), BNO055_QUATERNION_DATA_W_MSB_ADDR(
139 0X21), BNO055_QUATERNION_DATA_X_LSB_ADDR(
140 0X22), BNO055_QUATERNION_DATA_X_MSB_ADDR(
141 0X23), BNO055_QUATERNION_DATA_Y_LSB_ADDR(
142 0X24), BNO055_QUATERNION_DATA_Y_MSB_ADDR(
143 0X25), BNO055_QUATERNION_DATA_Z_LSB_ADDR(
144 0X26), BNO055_QUATERNION_DATA_Z_MSB_ADDR(0X27),
145
146 /* Linear acceleration data registers */
147 BNO055_LINEAR_ACCEL_DATA_X_LSB_ADDR(
148 0X28), BNO055_LINEAR_ACCEL_DATA_X_MSB_ADDR(
149 0X29), BNO055_LINEAR_ACCEL_DATA_Y_LSB_ADDR(
150 0X2A), BNO055_LINEAR_ACCEL_DATA_Y_MSB_ADDR(
151 0X2B), BNO055_LINEAR_ACCEL_DATA_Z_LSB_ADDR(
152 0X2C), BNO055_LINEAR_ACCEL_DATA_Z_MSB_ADDR(0X2D),
153
154 /* Gravity data registers */
155 BNO055_GRAVITY_DATA_X_LSB_ADDR(0X2E), BNO055_GRAVITY_DATA_X_MSB_ADDR(
156 0X2F), BNO055_GRAVITY_DATA_Y_LSB_ADDR(
157 0X30), BNO055_GRAVITY_DATA_Y_MSB_ADDR(
158 0X31), BNO055_GRAVITY_DATA_Z_LSB_ADDR(
159 0X32), BNO055_GRAVITY_DATA_Z_MSB_ADDR(0X33),
160
161 /* Temperature data register */
162 BNO055_TEMP_ADDR(0X34),
163
164 /* Status registers */
165 BNO055_CALIB_STAT_ADDR(0X35), BNO055_SELFTEST_RESULT_ADDR(
166 0X36), BNO055_INTR_STAT_ADDR(0X37),
167
168 BNO055_SYS_CLK_STAT_ADDR(0X38), BNO055_SYS_STAT_ADDR(
169 0X39), BNO055_SYS_ERR_ADDR(0X3A),
170
171 /* Unit selection register */
172 BNO055_UNIT_SEL_ADDR(0X3B), BNO055_DATA_SELECT_ADDR(0X3C),
173
174 /* Mode registers */
175 BNO055_OPR_MODE_ADDR(0X3D), BNO055_PWR_MODE_ADDR(0X3E),
176
177 BNO055_SYS_TRIGGER_ADDR(0X3F), BNO055_TEMP_SOURCE_ADDR(0X40),
178
179 /* Axis remap registers */
180 BNO055_AXIS_MAP_CONFIG_ADDR(0X41), BNO055_AXIS_MAP_SIGN_ADDR(0X42),
181
182 /* SIC registers */
183 BNO055_SIC_MATRIX_0_LSB_ADDR(0X43), BNO055_SIC_MATRIX_0_MSB_ADDR(
184 0X44), BNO055_SIC_MATRIX_1_LSB_ADDR(0X45), BNO055_SIC_MATRIX_1_MSB_ADDR(
185 0X46), BNO055_SIC_MATRIX_2_LSB_ADDR(
186 0X47), BNO055_SIC_MATRIX_2_MSB_ADDR(
187 0X48), BNO055_SIC_MATRIX_3_LSB_ADDR(
188 0X49), BNO055_SIC_MATRIX_3_MSB_ADDR(
189 0X4A), BNO055_SIC_MATRIX_4_LSB_ADDR(
190 0X4B), BNO055_SIC_MATRIX_4_MSB_ADDR(
191 0X4C), BNO055_SIC_MATRIX_5_LSB_ADDR(
192 0X4D), BNO055_SIC_MATRIX_5_MSB_ADDR(
193 0X4E), BNO055_SIC_MATRIX_6_LSB_ADDR(
194 0X4F), BNO055_SIC_MATRIX_6_MSB_ADDR(
195 0X50), BNO055_SIC_MATRIX_7_LSB_ADDR(
196 0X51), BNO055_SIC_MATRIX_7_MSB_ADDR(
197 0X52), BNO055_SIC_MATRIX_8_LSB_ADDR(
198 0X53), BNO055_SIC_MATRIX_8_MSB_ADDR(
199 0X54),
200
201 /* Accelerometer Offset registers */
202 ACCEL_OFFSET_X_LSB_ADDR(0X55), ACCEL_OFFSET_X_MSB_ADDR(
203 0X56), ACCEL_OFFSET_Y_LSB_ADDR(0X57), ACCEL_OFFSET_Y_MSB_ADDR(
204 0X58), ACCEL_OFFSET_Z_LSB_ADDR(0X59), ACCEL_OFFSET_Z_MSB_ADDR(0X5A),
205
206 /* Magnetometer Offset registers */
207 MAG_OFFSET_X_LSB_ADDR(0X5B), MAG_OFFSET_X_MSB_ADDR(
208 0X5C), MAG_OFFSET_Y_LSB_ADDR(0X5D), MAG_OFFSET_Y_MSB_ADDR(
209 0X5E), MAG_OFFSET_Z_LSB_ADDR(0X5F), MAG_OFFSET_Z_MSB_ADDR(0X60),
210
211 /* Gyroscope Offset register s */
212 GYRO_OFFSET_X_LSB_ADDR(0X61), GYRO_OFFSET_X_MSB_ADDR(
213 0X62), GYRO_OFFSET_Y_LSB_ADDR(0X63), GYRO_OFFSET_Y_MSB_ADDR(
214 0X64), GYRO_OFFSET_Z_LSB_ADDR(0X65), GYRO_OFFSET_Z_MSB_ADDR(0X66),
215
216 /* Radius registers */
217 ACCEL_RADIUS_LSB_ADDR(0X67), ACCEL_RADIUS_MSB_ADDR(
218 0X68), MAG_RADIUS_LSB_ADDR(0X69), MAG_RADIUS_MSB_ADDR(0X6A);
219
220 private final int val;
221
222 reg_t(int val) {
223 this.val = val;
224 }
225
226 public int getVal() {
227 return val;
228 }
229 };
230
231 public enum powermode_t {
232 POWER_MODE_NORMAL(0X00), POWER_MODE_LOWPOWER(0X01), POWER_MODE_SUSPEND(
233 0X02);
234
235 private final int val;
236
237 powermode_t(int val) {
238 this.val = val;
239 }
240
241 public int getVal() {
242 return val;
243 }
244 };
245
246 public enum opmode_t {
247 /* Operation mode settings */
248 OPERATION_MODE_CONFIG(0X00), OPERATION_MODE_ACCONLY(
249 0X01), OPERATION_MODE_MAGONLY(0X02), OPERATION_MODE_GYRONLY(
250 0X03), OPERATION_MODE_ACCMAG(0X04), OPERATION_MODE_ACCGYRO(
251 0X05), OPERATION_MODE_MAGGYRO(
252 0X06), OPERATION_MODE_AMG(0X07), OPERATION_MODE_IMUPLUS(
253 0X08), OPERATION_MODE_COMPASS(0X09), OPERATION_MODE_M4G(
254 0X0A), OPERATION_MODE_NDOF_FMC_OFF(
255 0X0B), OPERATION_MODE_NDOF(0X0C);
256
257 private final int val;
258
259 opmode_t(int val) {
260 this.val = val;
261 }
262
263 public int getVal() {
264 return val;
265 }
266 }
267
268 public class RevInfo {
269 public byte accel_rev;
270 public byte mag_rev;
271 public byte gyro_rev;
272 public short sw_rev;
273 public byte bl_rev;
274 }
275
276 public class CalData {
277 public byte sys;
278 public byte gyro;
279 public byte accel;
280 public byte mag;
281 }
282
283 public enum vector_type_t {
284 VECTOR_ACCELEROMETER(
285 reg_t.BNO055_ACCEL_DATA_X_LSB_ADDR.getVal()), VECTOR_MAGNETOMETER(
286 reg_t.BNO055_MAG_DATA_X_LSB_ADDR.getVal()), VECTOR_GYROSCOPE(
287 reg_t.BNO055_GYRO_DATA_X_LSB_ADDR.getVal()), VECTOR_EULER(
288 reg_t.BNO055_EULER_H_LSB_ADDR.getVal()), VECTOR_LINEARACCEL(
289 reg_t.BNO055_LINEAR_ACCEL_DATA_X_LSB_ADDR
290 .getVal()), VECTOR_GRAVITY(
291 reg_t.BNO055_GRAVITY_DATA_X_LSB_ADDR.getVal());
292
293 private final int val;
294
295 vector_type_t(int val) {
296 this.val = val;
297 }
298
299 public int getVal() {
300 return val;
301 }
302 };
303
304 /**
305 * Instantiates a new BNO055 class.
306 *
307 * @param port
308 * the physical port the sensor is plugged into on the roboRio
309 * @param address
310 * the address the sensor is at (0x28 or 0x29)
311 */
312 private BNO055(I2C.Port port, byte address) {
313 imu = new I2C(port, address);
314
315 executor = new java.util.Timer();
316 executor.schedule(new BNO055UpdateTask(this), 0L, THREAD_PERIOD);
317
f7a207f1 318 zeroReferenceConst = getHeading();
77875c79
ES
319
320 System.out.println("Initital Heading: " + zeroReferenceConst);
00ae4fb3
ES
321 }
322
323 /**
324 * Get an instance of the IMU object.
325 *
326 * @param mode
327 * the operating mode to run the sensor in.
328 * @param port
329 * the physical port the sensor is plugged into on the roboRio
330 * @param address
331 * the address the sensor is at (0x28 or 0x29)
332 * @return the instantiated BNO055 object
333 */
334 public static BNO055 getInstance(opmode_t mode, vector_type_t vectorType,
335 I2C.Port port, byte address) {
5c8bab72 336
00ae4fb3 337 if (instance == null) {
5c8bab72 338
00ae4fb3
ES
339 instance = new BNO055(port, address);
340 }
5c8bab72 341
00ae4fb3
ES
342 requestedMode = mode;
343 requestedVectorType = vectorType;
344 return instance;
345 }
346
347 /**
348 * Get an instance of the IMU object plugged into the onboard I2C header.
349 * Using the default address (0x28)
350 *
351 * @param mode
352 * the operating mode to run the sensor in.
353 * @param vectorType
354 * the format the position vector data should be returned
355 * in (if you don't know use VECTOR_EULER).
356 * @return the instantiated BNO055 object
357 */
358 public static BNO055 getInstance(opmode_t mode, vector_type_t vectorType) {
359 return getInstance(mode, vectorType, I2C.Port.kOnboard,
360 BNO055_ADDRESS_A);
361 }
362
363 /**
364 * Called periodically. Communicates with the sensor, and checks its state.
365 */
366 private void update() {
367 currentTime = Timer.getFPGATimestamp(); // seconds
368 if (!initialized) {
369 // System.out.println("State: " + state + ". curr: " + currentTime
370 // + ", next: " + nextTime);
371
372 // Step through process of initializing the sensor in a non-
373 // blocking manner. This sequence of events follows the process
374 // defined in the original adafruit source as closely as possible.
375 // XXX: It's likely some of these delays can be optimized out.
376 switch (state) {
377 case 0:
378 // Wait for the sensor to be present
379 if ((0xFF & read8(reg_t.BNO055_CHIP_ID_ADDR)) != BNO055_ID) {
380 // Sensor not present, keep trying
381 sensorPresent = false;
382 } else {
383 // Sensor present, go to next state
384 sensorPresent = true;
385 state++;
386 nextTime = Timer.getFPGATimestamp() + 0.050;
387 }
388 break;
389 case 1:
390 if (currentTime >= nextTime) {
391 // Switch to config mode (just in case since this is the default)
392 setMode(opmode_t.OPERATION_MODE_CONFIG.getVal());
393 nextTime = Timer.getFPGATimestamp() + 0.050;
394 state++;
395 }
396 break;
397 case 2:
398 // Reset
399 if (currentTime >= nextTime) {
400 write8(reg_t.BNO055_SYS_TRIGGER_ADDR, (byte) 0x20);
401 state++;
402 }
403 break;
404 case 3:
405 // Wait for the sensor to be present
406 if ((0xFF & read8(reg_t.BNO055_CHIP_ID_ADDR)) == BNO055_ID) {
407 // Sensor present, go to next state
408 state++;
409 // Log current time
410 nextTime = Timer.getFPGATimestamp() + 0.050;
411 }
412 break;
413 case 4:
414 // Wait at least 50ms
415 if (currentTime >= nextTime) {
416 /* Set to normal power mode */
417 write8(reg_t.BNO055_PWR_MODE_ADDR,
418 (byte) powermode_t.POWER_MODE_NORMAL.getVal());
419 nextTime = Timer.getFPGATimestamp() + 0.050;
420 state++;
421 }
422 break;
423 case 5:
424 // Use external crystal - 32.768 kHz
425 if (currentTime >= nextTime) {
426 write8(reg_t.BNO055_PAGE_ID_ADDR, (byte) 0x00);
427 nextTime = Timer.getFPGATimestamp() + 0.050;
428 state++;
429 }
430 break;
431 case 6:
432 if (currentTime >= nextTime) {
433 write8(reg_t.BNO055_SYS_TRIGGER_ADDR, (byte) 0x80);
434 nextTime = Timer.getFPGATimestamp() + 0.500;
435 state++;
436 }
437 break;
438 case 7:
439 // Set operating mode to mode requested at instantiation
440 if (currentTime >= nextTime) {
441 setMode(requestedMode);
442 nextTime = Timer.getFPGATimestamp() + 1.05;
443 state++;
444 }
445 break;
446 case 8:
447 if (currentTime >= nextTime) {
5c8bab72 448
f7a207f1 449 nextTime = Timer.getFPGATimestamp() + 1.05;
00ae4fb3
ES
450 state++;
451 }
452 case 9:
453 initialized = true;
454 break;
455 default:
456 // Should never get here - Fail safe
457 initialized = false;
458 }
459 } else {
460 // Sensor is initialized, periodically query position data
461 calculateVector();
462 }
463 }
464
465 /**
466 * Query the sensor for position data.
467 */
468 private void calculateVector() {
469 double[] pos = new double[3];
470 short x = 0, y = 0, z = 0;
471 double headingDiff = 0.0;
472
473 // Read vector data (6 bytes)
474 readLen(requestedVectorType.getVal(), positionVector);
475
476 x = (short) ((positionVector[0] & 0xFF)
477 | ((positionVector[1] << 8) & 0xFF00));
478 y = (short) ((positionVector[2] & 0xFF)
479 | ((positionVector[3] << 8) & 0xFF00));
480 z = (short) ((positionVector[4] & 0xFF)
481 | ((positionVector[5] << 8) & 0xFF00));
482
483 /* Convert the value to an appropriate range (section 3.6.4) */
484 /* and assign the value to the Vector type */
485 switch (requestedVectorType) {
486 case VECTOR_MAGNETOMETER:
487 /* 1uT = 16 LSB */
488 pos[0] = (x) / 16.0;
489 pos[1] = (y) / 16.0;
490 pos[2] = (z) / 16.0;
491 break;
492 case VECTOR_GYROSCOPE:
493 /* 1rps = 900 LSB */
494 pos[0] = (x) / 900.0;
495 pos[1] = (y) / 900.0;
496 pos[2] = (z) / 900.0;
497 break;
498 case VECTOR_EULER:
499 /* 1 degree = 16 LSB */
500 pos[0] = (x) / 16.0;
501 pos[1] = (y) / 16.0;
502 pos[2] = (z) / 16.0;
503 break;
504 case VECTOR_ACCELEROMETER:
505 case VECTOR_LINEARACCEL:
506 case VECTOR_GRAVITY:
507 /* 1m/s^2 = 100 LSB */
508 pos[0] = (x) / 100.0;
509 pos[1] = (y) / 100.0;
510 pos[2] = (z) / 100.0;
511 break;
512 }
513
514 // calculate turns
515 headingDiff = xyz[0] - pos[0];
516 if (Math.abs(headingDiff) >= 350) {
517 // We've traveled past the zero heading position
518 if (headingDiff > 0) {
519 turns++;
520 } else {
521 turns--;
522 }
523 }
524
525 // Update position vectors
526 xyz = pos;
527 }
528
529 /**
530 * Puts the chip in the specified operating mode
531 *
532 * @param mode
533 */
534 public void setMode(opmode_t mode) {
535 setMode(mode.getVal());
536 }
537
538 private void setMode(int mode) {
539 _mode = mode;
540 write8(reg_t.BNO055_OPR_MODE_ADDR, (byte) _mode);
541 }
542
543 /**
544 * Gets the latest system status info
545 *
546 * @return
547 */
548 public SystemStatus getSystemStatus() {
549 SystemStatus status = new SystemStatus();
550
551 write8(reg_t.BNO055_PAGE_ID_ADDR, (byte) 0x00);
552
553 /*
554 * System Status (see section 4.3.58)
555 * ---------------------------------
556 * 0 = Idle
557 * 1 = System Error
558 * 2 = Initializing Peripherals
559 * 3 = System Initalization
560 * 4 = Executing Self-Test
561 * 5 = Sensor fusion algorithm running
562 * 6 = System running without fusion algorithms
563 */
564
565 status.system_status = read8(reg_t.BNO055_SYS_STAT_ADDR);
566
567 /*
568 * Self Test Results (see section )
569 * --------------------------------
570 * 1 = test passed, 0 = test failed
571 *
572 * Bit 0 = Accelerometer self test
573 * Bit 1 = Magnetometer self test
574 * Bit 2 = Gyroscope self test
575 * Bit 3 = MCU self test
576 *
577 * 0x0F = all good!
578 */
579
580 status.self_test_result = read8(reg_t.BNO055_SELFTEST_RESULT_ADDR);
581
582 /*
583 * System Error (see section 4.3.59)
584 * ---------------------------------
585 * 0 = No error
586 * 1 = Peripheral initialization error
587 * 2 = System initialization error
588 * 3 = Self test result failed
589 * 4 = Register map value out of range
590 * 5 = Register map address out of range
591 * 6 = Register map write error
592 * 7 = BNO low power mode not available for selected operation mode
593 * 8 = Accelerometer power mode not available
594 * 9 = Fusion algorithm configuration error
595 * A = Sensor configuration error
596 */
597 status.system_error = read8(reg_t.BNO055_SYS_ERR_ADDR);
598 return status;
599 }
600
601 /**
602 * Gets the chip revision numbers
603 *
604 * @return the chips revision information
605 */
606 public RevInfo getRevInfo() {
607 int a = 0, b = 0;
608 RevInfo info = new RevInfo();
609
610 /* Check the accelerometer revision */
611 info.accel_rev = read8(reg_t.BNO055_ACCEL_REV_ID_ADDR);
612
613 /* Check the magnetometer revision */
614 info.mag_rev = read8(reg_t.BNO055_MAG_REV_ID_ADDR);
615
616 /* Check the gyroscope revision */
617 info.gyro_rev = read8(reg_t.BNO055_GYRO_REV_ID_ADDR);
618
619 /* Check the SW revision */
620 info.bl_rev = read8(reg_t.BNO055_BL_REV_ID_ADDR);
621
622 a = read8(reg_t.BNO055_SW_REV_ID_LSB_ADDR);
623 b = read8(reg_t.BNO055_SW_REV_ID_MSB_ADDR);
624 info.sw_rev = (short) ((b << 8) | a);
625
626 return info;
627 }
628
629 /**
630 * Diagnostic method to determine if communications with the sensor are
631 * active.
632 * Note this method returns true after first establishing communications
633 * with the sensor.
634 * Communications are not actively monitored once sensor initialization
635 * has started.
636 *
637 * @return true if the sensor is found on the I2C bus
638 */
639 public boolean isSensorPresent() {
640 return sensorPresent;
641 }
642
643 /**
644 * After power is applied, the sensor needs to be configured for use.
645 * During this initialization period the sensor will not return position
646 * vector data. Once initialization is complete, data can be read,
647 * although the sensor may not have completed calibration.
648 * See isCalibrated.
649 *
650 * @return true when the sensor is initialized.
651 */
652 public boolean isInitialized() {
653 return initialized;
654 }
655
656 /**
657 * Gets current calibration state.
658 *
659 * @return each value will be set to 0 if not calibrated, 3 if fully
660 * calibrated.
661 */
662 public CalData getCalibration() {
663 CalData data = new CalData();
664 int rawCalData = read8(reg_t.BNO055_CALIB_STAT_ADDR);
665
666 data.sys = (byte) ((rawCalData >> 6) & 0x03);
667 data.gyro = (byte) ((rawCalData >> 4) & 0x03);
668 data.accel = (byte) ((rawCalData >> 2) & 0x03);
669 data.mag = (byte) (rawCalData & 0x03);
670
671 return data;
672 }
673
674 /**
675 * Returns true if all required sensors (accelerometer, magnetometer,
676 * gyroscope) have completed their respective calibration sequence.
677 * Only sensors required by the current operating mode are checked.
678 * See Section 3.3.
679 *
680 * @return true if calibration is complete for all sensors required for the
681 * mode the sensor is currently operating in.
682 */
683 public boolean isCalibrated() {
684 boolean retVal = true;
685
686 // Per Table 3-3
687 boolean[][] sensorModeMap = new boolean[][] {
688 // {accel, mag, gyro}
689 { false, false, false }, // OPERATION_MODE_CONFIG
690 { true, false, false }, // OPERATION_MODE_ACCONLY
691 { false, true, false }, // OPERATION_MODE_MAGONLY
692 { false, false, true }, // OPERATION_MODE_GYRONLY
693 { true, true, false }, // OPERATION_MODE_ACCMAG
694 { true, false, true }, // OPERATION_MODE_ACCGYRO
695 { false, true, true }, // OPERATION_MODE_MAGGYRO
696 { true, true, true }, // OPERATION_MODE_AMG
697 { true, false, true }, // OPERATION_MODE_IMUPLUS
698 { true, true, false }, // OPERATION_MODE_COMPASS
699 { true, true, false }, // OPERATION_MODE_M4G
700 { true, true, true }, // OPERATION_MODE_NDOF_FMC_OFF
701 { true, true, true } // OPERATION_MODE_NDOF
702 };
703
704 CalData data = getCalibration();
705
706 if (sensorModeMap[_mode][0]) // Accelerometer used
707 retVal = retVal && (data.accel >= 3);
708 if (sensorModeMap[_mode][1]) // Magnetometer used
709 retVal = retVal && (data.mag >= 3);
710 if (sensorModeMap[_mode][2]) // Gyroscope used
711 retVal = retVal && (data.gyro >= 3);
712
713 return retVal;
714 }
715
716 /**
717 * Get the sensors internal temperature.
718 *
719 * @return temperature in degrees celsius.
720 */
721 public int getTemp() {
722 return (read8(reg_t.BNO055_TEMP_ADDR));
723 }
724
725 /**
726 * Gets a vector representing the sensors position (heading, roll, pitch).
727 * heading: 0 to 360 degrees
728 * roll: -90 to +90 degrees
729 * pitch: -180 to +180 degrees
730 *
731 * For continuous rotation heading (doesn't roll over between 360/0) see
732 * the getHeading() method.
733 *
734 * Maximum data output rates for Fusion modes - See 3.6.3
735 *
736 * Operating Mode Data Output Rate
737 * IMU 100 Hz
738 * COMPASS 20 Hz
739 * M4G 50 Hz
740 * NDOF_FMC_OFF 100 Hz
741 * NDOF 100 Hz
742 *
743 * @return a vector [heading, roll, pitch]
744 */
745 public double[] getVector() {
746 return xyz;
747 }
748
77875c79
ES
749 /**
750 * Heading not relative to the starting angle of the robot.
751 * Exists only for debugging purposes.
752 *
753 * @return
754 */
755 public double getRawHeading() {
756 return xyz[0] + turns * 360;
757 }
758
00ae4fb3
ES
759 /**
760 * The heading of the sensor (x axis) in continuous format. Eg rotating the
761 * sensor clockwise two full rotations will return a value of 720 degrees.
762 * The getVector method will return heading in a constrained 0 - 360 deg
763 * format if required.
764 *
765 * @return heading in degrees
766 */
767 public double getHeading() {
77875c79 768 double reading = getRawHeading();
f7a207f1 769
77875c79 770 return reading - zeroReferenceConst;
00ae4fb3
ES
771 }
772
773 /**
774 * Writes an 8 bit value over I2C
775 *
776 * @param reg
777 * the register to write the data to
778 * @param value
779 * a byte of data to write
780 * @return whatever I2CJNI.i2CWrite returns. It's not documented in the wpilib
781 * javadocs!
782 */
783 private boolean write8(reg_t reg, byte value) {
784 boolean retVal = false;
785
786 retVal = imu.write(reg.getVal(), value);
787
788 return retVal;
789 }
790
791 /**
792 * Reads an 8 bit value over I2C
793 *
794 * @param reg
795 * the register to read from.
796 * @return
797 */
798 private byte read8(reg_t reg) {
799 byte[] vals = new byte[1];
800
801 readLen(reg, vals);
802 return vals[0];
803 }
804
805 /**
806 * Reads the specified number of bytes over I2C
807 *
808 * @param reg
809 * the address to read from
810 * @param buffer
811 * to store the read data into
812 * @return true on success
813 */
814 private boolean readLen(reg_t reg, byte[] buffer) {
815 return readLen(reg.getVal(), buffer);
816 }
817
818 /**
819 * Reads the specified number of bytes over I2C
820 *
821 * @param reg
822 * the address to read from
823 * @param buffer
824 * the size of the data to read
825 * @return true on success
826 */
827 private boolean readLen(int reg, byte[] buffer) {
828 boolean retVal = true;
829
830 if (buffer == null || buffer.length < 1) {
831 return false;
832 }
833
834 retVal = !imu.read(reg, buffer.length, buffer);
835
836 return retVal;
837 }
838
839 private class BNO055UpdateTask extends TimerTask {
840 private BNO055 imu;
841
842 private BNO055UpdateTask(BNO055 imu) {
843 if (imu == null) {
844 throw new NullPointerException("BNO055 pointer null");
845 }
846 this.imu = imu;
847 }
848
849 /**
850 * Called periodically in its own thread
851 */
852 @Override
853 public void run() {
854 imu.update();
855 }
856 }
857}