Tool Libs
UMIT-TIROL Institute of Automation and Control Engineering library collection
 
Loading...
Searching...
No Matches
BNO085.h
Go to the documentation of this file.
1
5#pragma once
6
7#include "sys/i2c.h"
8#include "utils/slice.h"
9#include <cmath>
10#include <core/logger.h>
11
12
26 enum ADDR {
27 DEFAULT = 0b1001010,
28 ALT = 0b1001011,
29 };
30
32 enum Unit : uint8_t {
37 NONE,
38 };
39 static constexpr double rad2deg = 180. / M_PI;
40
42 struct Euler {
43 double yaw;
44 double pitch;
45 double roll;
49 if (u == unit) return *this;
50 switch (u) {
51 case RADIANS: return {
52 .yaw = yaw / rad2deg,
53 .pitch = pitch / rad2deg,
54 .roll = roll / rad2deg,
55 .unit = u,
56 };
57 case DEGREES: return {
58 .yaw = yaw * rad2deg,
59 .pitch = pitch * rad2deg,
60 .roll = roll * rad2deg,
61 .unit = u,
62 };
63 default: return {.yaw=0,.pitch=0,.roll=0,.unit=NONE};
64 }
65 }
66 };
67
69 struct Quaternion {
70 double r,i,j,k;
73 double sqr = r*r;
74 double sqi = i*i;
75 double sqj = j*j;
76 double sqk = k*k;
77 double factor = u==RADIANS ? 1. : rad2deg;
78
79 return {
80 .yaw = factor * atan2(2.0 * (i * j + k * r), (sqi - sqj - sqk + sqr)),
81 .pitch = factor * asin(-2.0 * (i * k - j * r) / (sqi + sqj + sqk + sqr)),
82 .roll = factor * atan2(2.0 * (j * k + i * r), (-sqi - sqj + sqk + sqr)),
83 .unit = u,
84 };
85 };
86 };
87
89 struct Rotation {
90 double x;
91 double y;
92 double z;
96 if (u == unit) return *this;
97 switch (u) {
98 case RADIANS: return {
99 .x = x / rad2deg,
100 .y = y / rad2deg,
101 .z = z / rad2deg,
102 .unit = u,
103 };
104 case DEGREES: return {
105 .x = x * rad2deg,
106 .y = y * rad2deg,
107 .z = z * rad2deg,
108 .unit = u,
109 };
110 default: return {.x=0,.y=0,.z=0,.unit=NONE};
111 }
112 }
113 };
114
124
125 BNO085(Sink<I2C::Request> &bus, uint8_t addr=DEFAULT) : I2C::Device{bus, addr} {}
126 using Data = Buffer<uint8_t>;
127 using View = Slice<uint8_t>;
128 int8_t read8(View d) { return d[0]; }
129 int16_t read16(View d) { return d[0] | d[1] << 8; }
130 int32_t read32(View d) { return d[0] | d[1] << 8 | d[2] << 16 | d[3] << 24; }
131
132 constexpr double Q(uint8_t p) {
133 return 1. / (1 << p);
134 }
135
136 enum Channel : uint8_t {
137 C_SHTP, C_DEV, C_CTRL, C_NORM, C_WAKE, C_GIRV, C_LAST,
138 };
139
140 uint8_t seq[C_LAST] {};
141
143 struct Message {
144 Channel chan;
145 Data cargo;
146 };
147
148 struct Transaction {
149 struct Operation {
150 Message msg;
151 uint8_t rsp; // ID of response message
152 int16_t seq = -1; // used as 'in-flight' flag + matching
153 };
155 bool active = false;
156 };
157
161 uint8_t sendMessage(const Message &msg) {
162 Data data = msg.cargo.len + 4;
163 uint8_t sq = seq[msg.chan]++;
164 // build header
165 data.append({
166 (uint8_t) data.size, (uint8_t)(data.size >> 8),
167 msg.chan, sq,
168 });
169 for (auto &d: msg.cargo) data.append(d);
170 bus.trypush({
171 .dev = this,
172 .data = data,
173 });
174 return sq-1;
175 }
176
177 void sendTransaction(Queue<Transaction> &q, Transaction &&t) {
178 if (q.full()) return; // drop transaction. something went wrong
179 q.push(std::move(t));
180 if (q.front().active == false) sendQueued(q);
181 }
182
183 void sendQueued(Queue<Transaction> &q) {
184 if (q.empty()) return;
185 auto &t = q.front();
186 if (t.active) return; // still in flight
187 t.active = true;
188 if (t.q.empty()) return; //XXX: or just pop outer & sendQueued(q)
189 auto &oper = t.q.front();
190 if (oper.seq != -1) return; // still in flight. shouldn't get here.
191 oper.seq = sendMessage(oper.msg);
192 }
193
194 enum Commands : uint8_t { CMD_GET_ADV, CMD_GET_ERR };
195
196 void getAdvertisement(bool all) {
198 .chan = C_SHTP,
199 .cargo = {CMD_GET_ADV, all},
200 });
201 }
202 void getErrors() {
204 .chan = C_SHTP,
205 .cargo = {CMD_GET_ERR},
206 });
207 }
208
209 enum AdvTag : uint8_t {
210 RESERVED, GUID, MAX_CPH_WRITE, MAX_CPH_READ, MAX_XFER_WRITE, MAX_XFER_READ,
211 NORMAL_CH, WAKE_CH, APP_NAME, CH_NAME
212 };
213
214 void logAdvertisement(View data) {
215 lg->info("advertisement\n");
216 uint8_t last_guid {};
217 while (data.len) {
218 assert (data.len > 2);
219 AdvTag tag {data[0]};
220 size_t len {data[1]};
221 int val;
222 switch (len) {
223 case 1: val = read8({data,2}); break;
224 case 2: val = read16({data,2}); break;
225 case 4: val = read32({data,2}); break;
226 }
227 switch ((uint8_t)tag) {
228 case GUID: last_guid = val;
229 lg->print("GUID: %d\n", val); break;
230 case MAX_CPH_WRITE:
231 lg->print("MaxCargoPlusHeaderWrite: %d\n", val); break;
232 case MAX_CPH_READ:
233 lg->print("MaxCargoPlusHeaderRead: %d\n", val); break;
234 case MAX_XFER_WRITE:
235 lg->print("MaxTransferWrite: %d\n", val); break;
236 case MAX_XFER_READ:
237 lg->print("MaxTransferRead: %d\n", val); break;
238 case NORMAL_CH:
239 lg->print("NormalChannel: %d\n", val); break;
240 case WAKE_CH:
241 lg->print("WakeChannel: %d\n", val); break;
242 case APP_NAME:
243 lg->print("AppName: %.*s\n", len, &data[2]); break;
244 case CH_NAME:
245 lg->print("ChannelName: %.*s\n", len, &data[2]); break;
246 case 0x80:
247 if (last_guid == 0) {
248 lg->print("SHTP Version: %.*s\n", len, &data[2]); break;
249 } else {
250 lg->print("Version: %.*s\n", len, &data[2]); break;
251 }
252 case 0x81:
253 if (last_guid == 0) {
254 lg->print("SHTP Timeout: %dms\n", val); break;
255 } else {
256 lg->print("Report Lengths:\n");
257 auto rpl = Slice{data,2};
258 for ( size_t i = 0; i < rpl.len; i+=2) {
259 lg->print("\t[ 0x%.2x : %d ]\n", rpl[i], rpl[i+1]);
260 }
261 break;
262 }
263 default:
264 lg->print("Wrong Tag [%d], len [%d]\n", tag, len); break;
265 }
266 data = Slice{data, len+2};
267 }
268 }
269
270 enum ERR : uint8_t {
271 NO_ERR, MAX_READ_EXCEED, HOST_WRITE_SHORT, MAX_WRITE_EXCEED, HOST_WRITE_INVALID,
272 FRAGMENT_UNSUPPORTED_START, FRAGMENT_UNSUPPORTED_CONT, CMD_NOT_RECOGNIZED, PARAM_NOT_RECOGNIZED,
273 CHANNEL_NOT_RECOGNIZED, REQ_WHILE_PENDING, WRITE_WHILE_RESP, ERR_TRUNC_LIST,
274 };
275
276 void logErrorList(View data) {
277 lg->info("error list\n");
278 for (auto &d: data) {
279 ERR err {d};
280 switch (err) {
281 case NO_ERR: lg->print("\tNO_ERR\n", err); break;
282 case MAX_READ_EXCEED: lg->print("\tMAX_READ_EXCEED\n", err); break;
283 case HOST_WRITE_SHORT: lg->print("\tHOST_WRITE_SHORT\n", err); break;
284 case MAX_WRITE_EXCEED: lg->print("\tMAX_WRITE_EXCEED\n", err); break;
285 case HOST_WRITE_INVALID: lg->print("\tHOST_WRITE_INVALID\n", err); break;
286 case FRAGMENT_UNSUPPORTED_START: lg->print("\tFRAGMENT_UNSUPPORTED_START\n", err); break;
287 case FRAGMENT_UNSUPPORTED_CONT: lg->print("\tFRAGMENT_UNSUPPORTED_CONT\n", err); break;
288 case CMD_NOT_RECOGNIZED: lg->print("\tCMD_NOT_RECOGNIZED\n", err); break;
289 case PARAM_NOT_RECOGNIZED: lg->print("\tPARAM_NOT_RECOGNIZED\n", err); break;
290 case CHANNEL_NOT_RECOGNIZED: lg->print("\tCHANNEL_NOT_RECOGNIZED\n", err); break;
291 case REQ_WHILE_PENDING: lg->print("\tREQ_WHILE_PENDING\n", err); break;
292 case WRITE_WHILE_RESP: lg->print("\tWRITE_WHILE_RESP\n", err); break;
293 case ERR_TRUNC_LIST: lg->print("\tERR_TRUNC_LIST\n", err); break;
294 }
295 }
296 }
297
298 void handleSHTP(View cargo) {
299 if (lg) lg->print("Response Handler: ");
300 switch (cargo[0]) {
301 case CMD_GET_ADV: if(lg) logAdvertisement({cargo, 1}); break;
302 case CMD_GET_ERR: if(lg) logErrorList({cargo, 1}); break;
303 default: if(lg) lg->warn("unknown SHTP response: [%d]\n", cargo[0]);
304 }
305 }
306
307 void handleWakeNormal(View cargo) {
308 while (cargo.len) switch (cargo[0]) {
309 case 0x05: cargo = handleRotVecReport(cargo); break;
310 case 0xFA: cargo = handleRebaseTimeStamp(cargo); break;
311 case 0xFB: cargo = handleBaseTimeStamp(cargo); break;
312 case 0xFC: cargo = handleFeatureResponse(cargo); break;
313 default:
314 if (lg) lg->warn("unrecognized Report: [0x%.2x]\n", cargo[0]);
315 if (lg) logData({*cargo.buf,0});
316 return;
317 }
318 }
319
320 View handleRotVecReport(View cargo) {
321 assert(cargo[0] == 0x05); // report ID
322 this->rotvec = {
323 .r = read16({cargo, 10}) * Q(14),
324 .i = read16({cargo, 4}) * Q(14),
325 .j = read16({cargo, 6}) * Q(14),
326 .k = read16({cargo, 8}) * Q(14),
327 };
328 this->rotvec_accuracy = read16({cargo, 12}) * Q(12);
329 return {cargo, 14};
330 }
331
332 void handleGIRV(View cargo) {
333 // note: does not contain report ID
334 this->girv.pose = {
335 .r = read16({cargo, 6}) * Q(14),
336 .i = read16({cargo, 0}) * Q(14),
337 .j = read16({cargo, 2}) * Q(14),
338 .k = read16({cargo, 4}) * Q(14),
339 };
340 this->girv.rot = {
341 .x = read16({cargo, 8}) * Q(10),
342 .y = read16({cargo, 10}) * Q(10),
343 .z = read16({cargo, 12}) * Q(10),
344 .unit = RADIANS,
345 };
346 }
347
348 View handleBaseTimeStamp(View cargo) {
349 assert(cargo[0] == 0xFB); // report ID
350 int32_t tb_delta = read32({cargo, 1});
351 (void) tb_delta;
352 return {cargo, 5};
353 }
354
355 View handleRebaseTimeStamp(View cargo) {
356 assert(cargo[0] == 0xFA); // report ID
357 int32_t rb_delta = read32({cargo, 1});
358 (void) rb_delta;
359 return {cargo, 5};
360 }
361
362 void logData(View cargo) {
363 for (uint8_t c: cargo) {
364 lg->print("%#x ", c);
365 }
366 lg->print("\n");
367 }
368
369 struct Feature {
370 uint32_t report_interval, batch_interval, config_word;
371 uint16_t sensitivity;
372 uint8_t flags;
373 uint8_t reportID;
374 };
375
376 void setFeature(Feature feat) {
378 .chan = C_CTRL,
379 .cargo = {
380 0xFD, feat.reportID, feat.flags,
381 (uint8_t)feat.sensitivity, (uint8_t)(feat.sensitivity>>8),
382 (uint8_t)(feat.report_interval >> 0),
383 (uint8_t)(feat.report_interval >> 8),
384 (uint8_t)(feat.report_interval >> 16),
385 (uint8_t)(feat.report_interval >> 24),
386 (uint8_t)(feat.batch_interval >> 0),
387 (uint8_t)(feat.batch_interval >> 8),
388 (uint8_t)(feat.batch_interval >> 16),
389 (uint8_t)(feat.batch_interval >> 24),
390 (uint8_t)(feat.config_word >> 0),
391 (uint8_t)(feat.config_word >> 8),
392 (uint8_t)(feat.config_word >> 16),
393 (uint8_t)(feat.config_word >> 24),
394 },
395 });
396 }
397
398 View handleFeatureResponse(View cargo) {
399 (void)cargo;
400 if (lg) lg->print("handling Feature Response.. TODO\n");
401 return {cargo, 17};
402 }
403
404 struct {
405 Queue<Transaction> write, read;
406 } qs;
407
408 void handleControl(View cargo) {
409 switch (cargo[0]) {
410 case 0xF5: handleFRSWriteResponse(cargo); return;
411 case 0xF3: handleFRSReadResponse(cargo); return;
412 default: if (lg) {
413 lg->warn("unhandled message on control channel: [%#x]\n", cargo[0]);
414 logData({*cargo.buf, 0});
415 }
416 }
417 }
418
419 void handleFRSWriteResponse(View d) {
420 assert(d[0] == 0xF5);
421 if (qs.write.empty()) return; //something went wrong
422 auto &t = qs.write.front();
423 if (t.q.empty()) return; //something went wrong
424 auto &op = t.q.front();
425 if (op.rsp != 0xF5 && lg) lg->warn("response 0xF5, expected [%#x]\n", op.rsp);
426 if (lg) logFRSWriteResponse(d);
427 uint8_t status = d[1];
428 switch (status) {
429 // operation finished
430 case 0: if (!t.q.empty()) {
431 t.q.drop();
432 sendQueued(qs.write);
433 }
434 break;
435 // progress
436 case 8: break;
437 // error or transaction done
438 default: if (!qs.write.empty()) {
439 qs.write.drop();
440 sendQueued(qs.write);
441 }
442 break;
443 }
444 }
445
446 void logFRSWriteResponse(View d) {
447 uint8_t status = d[1];
448 uint16_t word = read16({d, 2});
449 lg->info("FRS Write Response: offset [%d]\n", word);
450 switch (status) {
451 case 0: lg->print("Word(s) received\n"); break;
452 case 1: lg->print("unrecognized FRS type\n"); break;
453 case 2: lg->print("busy\n"); break;
454 case 3: lg->print("write completed\n"); break;
455 case 4: lg->print("write mode ready\n"); break;
456 case 5: lg->print("write failed\n"); break;
457 case 6: lg->print("data received while not in write mode\n"); break;
458 case 7: lg->print("invalid length\n"); break;
459 case 8: lg->print("record valid\n"); break;
460 case 9: lg->print("record invalid\n"); break;
461 case 10: lg->print("device error\n"); break;
462 case 11: lg->print("record is read only\n"); break;
463 case 12: lg->print("FRS memory is full\n"); break;
464 }
465 }
466
467 void handleFRSReadResponse(View d) {
468 assert(d[0] == 0xF3);
469 if (lg) logFRSReadResponse(d);
470 uint8_t status = d[1] & 0xf;
471 switch (status) {
472 case 0: // progress
473 break;
474 default: // complete or error
475 qs.read.pop(); sendQueued(qs.read); break;
476 }
477 }
478
479 void logFRSReadResponse(View d) {
480 lg->info("FRS Read Response:\n");
481 uint8_t len = d[1] >> 4;
482 uint8_t status = d[1] & 0xf;
483 uint16_t offset = read16({d, 2});
484 uint32_t w0 = read32({d, 4});
485 uint32_t w1 = read32({d, 8});
486 switch (status) {
487 case 0: lg->print("no error\n"); break;
488 case 1: lg->warn("unrecognized FRS type [0x%.4x]\n", read16({d,12})); break;
489 case 2: lg->print("busy\n"); break;
490 case 3: lg->print("read record completed\n"); break;
491 case 5: lg->print("record empty\n"); break;
492 case 8: lg->print("device error\n"); break;
493 }
494 lg->print("offset: %d\n", offset);
495 lg->print("length of data: %d\n", len);
496 lg->print("data0: %#x\n", w0);
497 lg->print("data1: %#x\n", w1);
498 lg->print("FRS Type: %#x\n", (uint16_t)read16({d,12}));
499 }
500
501 void readFRS(uint16_t type) {
502 Transaction t {
504 .msg = {
505 .chan = C_CTRL,
506 .cargo = {
507 // FRS Read request
508 0xF4,
509 0, 0, 0, //reserved
510 (uint8_t)type, (uint8_t)(type>>8),
511 0, 0,
512 },
513 },
514 .rsp = 0xF3,
515 }},
516 .active = false,
517 };
518 sendTransaction(qs.read, std::move(t));
519 }
520
521 struct GIRVConfig {
522 enum Reference : uint16_t {
523 GameRotVec_6Ax = 0x0207,
524 AbsRotVec_9Ax = 0x0204,
525 } ref = GameRotVec_6Ax;
526 uint32_t sync = 10000; // ref sync in microseconds
527 uint32_t max_err = 0x10c15238; // pi/6 @ Qpoint of 29
528 uint32_t prediction = 0; // in seconds, Qpoint of 10
529 uint32_t alpha = 0; // 0.303072543909142
530 uint32_t beta = 0; // 0.113295896384921
531 uint32_t gamma = 0; // 0.002776219713054
532 };
533
534 void configure(GIRVConfig cfg) {
535 // configuration recordID = 0xA1A2
536 // FRS recordID = 0xE324
537 Transaction t {
539 .msg = {
540 .chan = C_CTRL,
541 .cargo = {
542 0xF7, // FRS write request
543 0, // reserved
544 7, 0, //length of record in WORDS
545 0xa2, 0xa1, //configuration record id
546 },
547 },
548 .rsp = 0xF5,
549 }, {
550 .msg = {
551 .chan = C_CTRL,
552 .cargo = {
553 0xF6, // FRS write data request
554 0, //reserved
555 0, 0, //offset
556 (uint8_t)cfg.ref, (uint8_t)(cfg.ref >> 8),
557 0, 0,
558 (uint8_t)cfg.sync, (uint8_t)(cfg.sync >> 8),
559 (uint8_t)(cfg.sync >> 16), (uint8_t)(cfg.sync >> 24),
560 },
561 },
562 .rsp = 0xF5,
563 }, {
564 .msg = {
565 .chan = C_CTRL,
566 .cargo = {
567 0xF6, // FRS write data request
568 0, //reserved
569 2, 0, //offset
570 (uint8_t)cfg.max_err, (uint8_t)(cfg.max_err >> 8),
571 (uint8_t)(cfg.max_err >> 16), (uint8_t)(cfg.max_err >> 24),
572 (uint8_t)cfg.prediction, (uint8_t)(cfg.prediction >> 8),
573 (uint8_t)(cfg.prediction >> 16), (uint8_t)(cfg.prediction >> 24),
574 },
575 },
576 .rsp = 0xF5,
577 }, {
578 .msg = {
579 .chan = C_CTRL,
580 .cargo = {
581 0xF6, // FRS write data request
582 0, //reserved
583 4, 0, //offset
584 (uint8_t)cfg.alpha, (uint8_t)(cfg.alpha >> 8),
585 (uint8_t)(cfg.alpha >> 16), (uint8_t)(cfg.alpha >> 24),
586 (uint8_t)cfg.beta, (uint8_t)(cfg.beta >> 8),
587 (uint8_t)(cfg.beta >> 16), (uint8_t)(cfg.beta >> 24),
588 },
589 },
590 .rsp = 0xF5,
591 }, {
592 .msg = {
593 .chan = C_CTRL,
594 .cargo = {
595 0xF6, // FRS write data request
596 0, //reserved
597 6, 0, //offset
598 (uint8_t)cfg.gamma, (uint8_t)(cfg.gamma >> 8),
599 (uint8_t)(cfg.gamma >> 16), (uint8_t)(cfg.gamma >> 24),
600 0,0,0,0,
601 },
602 },
603 .rsp = 0xF5,
604 }}
605 };
606 sendTransaction(qs.write, std::move(t));
607 }
608
609 void callback(const I2C::Request &rq) override {
610 if (!rq.opts.read) {
611 //delete
612 /* if (rq.data.len >4) { */
613 /* lg->info("sent: "); */
614 /* logData({rq.data,0}); */
615 /* } */
616 //delete
617 return; // do nothing on successful writes
618 }
619
620 if (rq.data.len >= 4) {
621 /* bool continuation = rq.data[1] & 0x80; */
622 const unsigned int len = (uint16_t)(rq.data[1] & 0x7f) << 8 | rq.data[0];
623 if (len == 0xffff) return; // 'length of 65535 is an error.'
624 const Channel chan = (Channel)rq.data[2];
625 const uint8_t seq = rq.data[3];
626 if (len == 0) return; // length of 0 indicates 'no data'
627 if (seq != this->seq[chan]) {
628 //error?
629 if (lg) lg->warn("expected seq: %d, got %d\n", this->seq[chan], seq);
630 }
631 this->seq[chan] = seq + 1;
632 if (len > rq.data.len) { // need to get more data
633 bus.trypush({
634 .dev = this,
635 .data = len,
636 .opts = {
637 .read = true,
638 },
639 });
640 return;
641 }
642
643 View data {rq.data, 4};
644 switch (chan) {
645 case C_SHTP: handleSHTP(data); return;
646 /* case C_DEV: handleDevice(data); return; */
647 case C_CTRL: handleControl(data); return;
648 case C_NORM ... C_WAKE: handleWakeNormal(data); return;
649 case C_GIRV: handleGIRV(data); return;
650 default:
651 if (lg) {
652 lg->print("unrecognized data:\n");
653 logData({rq.data, 0});
654 }
655 }
656
657 }
658 }
659
660 double rotvec_accuracy;
667
671 void poll(uint32_t, uint32_t) {
672 bus.trypush({
673 .dev = this,
674 .data = 4,
675 .opts = { .read = true },
676 });
677 }
678
680 void enableRotVec(uint32_t Hz=400) {
681 setFeature({
682 .report_interval = 1'000'000 / Hz,
683 .reportID = 0x05,
684 });
685 }
686
689 setFeature({
690 .report_interval = 0,
691 .reportID = 0x05,
692 });
693 }
694
696 void enableGIRV(uint32_t Hz=500) {
697 configure({
698 .ref = GIRVConfig::AbsRotVec_9Ax,
699 });
700 setFeature({
701 .report_interval = 1'000'000 / Hz,
702 .reportID = 0x2a,
703 });
704 }
705
707 void disableGIRV() {
708 setFeature({
709 .report_interval = 0,
710 .reportID = 0x2a,
711 });
712 }
713
715 void restart() {
717 .chan = C_DEV,
718 .cargo = { 1 },
719 });
720 }
721
727 switch (u) {
728 case RADIANS: return rotvec_accuracy;
729 case DEGREES: return rotvec_accuracy * rad2deg;
730 default: return 0;
731 }
732 }
733
734 BufferedLogger *lg = nullptr;
735};
simple Buffer backed queue implementation
Definition queue.h:12
bool empty() override
check if queue is empty
Definition queue.h:83
bool full() override
return true if queue is full
Definition queue.h:87
void push(T &&val) override
move element into queue
Definition queue.h:49
T & front()
return reference to first element in queue
Definition queue.h:55
Copyright (c) 2023 IACE.
Copyright (c) 2023 IACE.
Copyright (c) 2025 IACE.
Euler angles.
Definition BNO085.h:42
Euler toUnit(Unit u)
Convert to given Unit.
Definition BNO085.h:48
double yaw
yaw
Definition BNO085.h:43
double pitch
pitch
Definition BNO085.h:44
double roll
roll
Definition BNO085.h:45
Unit unit
unit of entries
Definition BNO085.h:46
Quaternion of pose.
Definition BNO085.h:69
Euler toEuler(Unit u=RADIANS) const
return pose in euler angles, in given Unit
Definition BNO085.h:72
Rotation about axes, in given Unit/s.
Definition BNO085.h:89
double x
rotation around x-axis, in unit/s
Definition BNO085.h:90
Unit unit
Unit per second.
Definition BNO085.h:93
Rotation toUnit(Unit u)
Convert to given Unit per second.
Definition BNO085.h:95
double y
rotation around y-axis, in unit/s
Definition BNO085.h:91
double z
rotation around z-axis, in unit/s
Definition BNO085.h:92
Implementation of the BNO085 9-axis motion processor.
Definition BNO085.h:24
uint8_t sendMessage(const Message &msg)
simple fire & forget message sending returns the sequence of sent message
Definition BNO085.h:161
double accuracy(Unit u=RADIANS)
return approximated accuracy in given Unit
Definition BNO085.h:726
void disableRotVec()
disable high-accuracy rotation vector
Definition BNO085.h:688
ADDR
possible I2C addresses
Definition BNO085.h:26
@ DEFAULT
0x4a
Definition BNO085.h:27
@ ALT
0x4b
Definition BNO085.h:28
void enableGIRV(uint32_t Hz=500)
enable high-speed GIRV at given frequency
Definition BNO085.h:696
void poll(uint32_t, uint32_t)
call this regularly to make sure we receive messages from the device when it wants to send them
Definition BNO085.h:671
void callback(const I2C::Request &rq) override
callback.
Definition BNO085.h:609
GIRV girv
high-speed Gyro-Integrated Rotation Vector, includes estimation of rotation velocities
Definition BNO085.h:666
Quaternion rotvec
high-accuracy 9-axis sensor-fused rotation vector
Definition BNO085.h:662
void restart()
restart the device
Definition BNO085.h:715
void disableGIRV()
disable high-speed GIRV
Definition BNO085.h:707
Rotation rot
estimation of rotation velocities
Definition BNO085.h:122
Unit
Enum for defining wanted Units of angles.
Definition BNO085.h:32
@ RADIANS
return values in radians
Definition BNO085.h:34
@ DEGREES
return values in degrees
Definition BNO085.h:36
void enableRotVec(uint32_t Hz=400)
enable high-accuracy rotation vector at given frequency
Definition BNO085.h:680
Quaternion pose
estimation of pose
Definition BNO085.h:120
high-speed Gyro-Integrated Rotation Vector includes estimation of rotation velocities
Definition BNO085.h:118
SHTP Message.
Definition BNO085.h:143
dynamically allocated, but fixed-size buffer template
Definition buffer.h:18
Buffer & append(T b)
simple append single item
Definition buffer.h:44
size_t size
total capacity of buffer
Definition buffer.h:23
size_t len
number of items stored in buffer
Definition buffer.h:21
buffered logging facility
Definition logger.h:81
generic I2C device wrapper.
Definition i2c.h:21
Device(Sink< Request > &bus, uint8_t address)
construct device on bus with given address
Definition i2c.h:26
struct defining an I2C request.
Definition i2c.h:37
Buffer< uint8_t > data
transfer data
Definition i2c.h:39
union I2C::Request::Type opts
transfer options.
void print(const char *fmt,...)
None log level.
Definition logger.h:57
void info(const char *fmt,...)
Info log level.
Definition logger.h:43
void warn(const char *fmt,...)
Warn log level.
Definition logger.h:50
Class implementing reference interpolation.
Definition trajectory.h:167
generic object sink, i.e.
Definition streams.h:15
void trypush(T &&t)
use this if you don't care if it's going to be successful. data gets discarded if sink is full.
Definition streams.h:28
slice of existing Buffer.
Definition slice.h:12