68
68
_SAVE_DCD = const (0x6 )
69
69
_ME_CALIBRATE = const (0x7 )
70
70
_ME_CAL_CONFIG = const (0x00 )
71
+ _ME_GET_CAL = const (0x01 )
71
72
72
73
# Calibrated Acceleration (m/s2)
73
74
BNO_REPORT_ACCELEROMETER = const (0x01 )
179
180
["channel_number" , "sequence_number" , "data_length" , "packet_byte_count" ,],
180
181
)
181
182
182
- REPORT_STATUS = ["Unreliable" , "Accuracy low" , "Accuracy medium" , "Accuracy high" ]
183
+ REPORT_ACCURACY_STATUS = [
184
+ "Accuracy Unreliable" ,
185
+ "Low Accuracy" ,
186
+ "Medium Accuracy" ,
187
+ "High Accuracy" ,
188
+ ]
183
189
184
190
185
191
class PacketError (Exception ):
@@ -218,14 +224,17 @@ def _parse_sensor_report_data(report_bytes):
218
224
else :
219
225
format_str = "<h"
220
226
results = []
227
+ accuracy = unpack_from ("<B" , report_bytes , offset = 2 )[0 ]
228
+ accuracy &= 0b11
221
229
222
230
for _offset_idx in range (count ):
223
231
total_offset = data_offset + (_offset_idx * 2 )
224
232
raw_data = unpack_from (format_str , report_bytes , offset = total_offset )[0 ]
225
233
scaled_data = raw_data * scalar
226
234
results .append (scaled_data )
235
+ results_tuple = tuple (results )
227
236
228
- return tuple ( results )
237
+ return ( results_tuple , accuracy )
229
238
230
239
231
240
def _parse_step_couter_report (report_bytes ):
@@ -336,7 +345,7 @@ def _insert_command_request_report(
336
345
return
337
346
338
347
for idx , param in enumerate (command_params ):
339
- buffer [4 + 3 + idx ] = param
348
+ buffer [3 + idx ] = param
340
349
341
350
342
351
def _report_length (report_id ):
@@ -477,7 +486,7 @@ def is_error(cls, header):
477
486
return False
478
487
479
488
480
- class BNO08X :
489
+ class BNO08X : # pylint: disable=too-many-instance-attributes, too-many-public-methods
481
490
"""Library for the BNO08x IMUs from Hillcrest Laboratories
482
491
483
492
:param ~busio.I2C i2c_bus: The I2C bus the BNO08x is connected to.
@@ -500,8 +509,8 @@ def __init__(self, reset=None, debug=False):
500
509
}
501
510
self ._dcd_saved_at = - 1
502
511
self ._me_calibration_started_at = - 1
503
- # self._sequence_number = {"in": [0, 0, 0, 0, 0, 0], "out": [0, 0, 0, 0, 0, 0]}
504
- # sef
512
+ self ._calibration_complete = False
513
+ self . _magnetometer_accuracy = 0
505
514
self ._wait_for_initialize = True
506
515
self ._init_complete = False
507
516
self ._id_read = False
@@ -696,6 +705,7 @@ def raw_magnetic(self):
696
705
raise RuntimeError ("No raw magnetic report found, is it enabled?" ) from None
697
706
698
707
def begin_calibration (self ):
708
+ """Begin the sensor's self-calibration routine"""
699
709
# start calibration for accel, gyro, and mag
700
710
self ._send_me_command (
701
711
[
@@ -710,6 +720,25 @@ def begin_calibration(self):
710
720
0 , # reserved
711
721
]
712
722
)
723
+ self ._calibration_complete = False
724
+
725
+ @property
726
+ def calibration_status (self ):
727
+ """Get the status of the self-calibration"""
728
+ self ._send_me_command (
729
+ [
730
+ 0 , # calibrate accel
731
+ 0 , # calibrate gyro
732
+ 0 , # calibrate mag
733
+ _ME_GET_CAL ,
734
+ 0 , # calibrate planar acceleration
735
+ 0 , # 'on_table' calibration
736
+ 0 , # reserved
737
+ 0 , # reserved
738
+ 0 , # reserved
739
+ ]
740
+ )
741
+ return self ._magnetometer_accuracy
713
742
714
743
def _send_me_command (self , subcommand_params ):
715
744
@@ -718,7 +747,7 @@ def _send_me_command(self, subcommand_params):
718
747
_insert_command_request_report (
719
748
_ME_CALIBRATE ,
720
749
self ._command_buffer , # should use self._data_buffer :\ but send_packet don't
721
- self .get_report_seq_id (_COMMAND_REQUEST ),
750
+ self ._get_report_seq_id (_COMMAND_REQUEST ),
722
751
subcommand_params ,
723
752
)
724
753
self ._send_packet (_BNO_CHANNEL_CONTROL , local_buffer )
@@ -727,53 +756,32 @@ def _send_me_command(self, subcommand_params):
727
756
self ._process_available_packets ()
728
757
if self ._me_calibration_started_at > start_time :
729
758
break
730
- print ("ME Started?" )
731
759
732
760
def save_calibration_data (self ):
761
+ """Save the self-calibration data"""
733
762
# send a DCD save command
734
- # _COMMAND_REQUEST = const(0xF2)
735
- # _COMMAND_RESPONSE = const(0xF1)
736
763
start_time = time .monotonic ()
737
764
local_buffer = bytearray (12 )
738
765
_insert_command_request_report (
739
766
_SAVE_DCD ,
740
767
local_buffer , # should use self._data_buffer :\ but send_packet don't
741
- self .get_report_seq_id (_COMMAND_REQUEST ),
768
+ self ._get_report_seq_id (_COMMAND_REQUEST ),
742
769
)
743
770
self ._send_packet (_BNO_CHANNEL_CONTROL , local_buffer )
744
771
self ._increment_report_seq (_COMMAND_REQUEST )
745
772
while _elapsed (start_time ) < _DEFAULT_TIMEOUT :
746
773
self ._process_available_packets ()
747
774
if self ._dcd_saved_at > start_time :
748
- break
749
- print ("DCD SAVED?" )
750
- # Byte Description
751
- # 0 Report ID = 0xF2
752
- # 1 Sequence number
753
- # 2 Command
754
- # P0-9: a set of command-specific parameters. The interpretation of these
755
- # parameters is defined for each command.
756
- # 3 P0
757
- # 4 P1
758
- # 5 P2
759
- # 6 P3
760
- # 7 P4
761
- # 8 P5
762
- # 9 P6
763
- # 10 P7
764
- # 11 P8
765
-
766
- # poll on DCD calibration status
767
-
768
- # TODO: Make this a Packet creation
769
-
770
- self ._increment_report_seq (_COMMAND_REQUEST )
775
+ return
776
+ raise RuntimeError ("Could not save calibration data" )
771
777
772
778
############### private/helper methods ###############
773
779
# # decorator?
774
- def _process_available_packets (self ):
780
+ def _process_available_packets (self , max_packets = None ):
775
781
processed_count = 0
776
782
while self ._data_ready :
783
+ if max_packets and processed_count > max_packets :
784
+ return
777
785
# print("reading a packet")
778
786
try :
779
787
new_packet = self ._read_packet ()
@@ -866,15 +874,18 @@ def _handle_control_report(self, report_id, report_bytes):
866
874
867
875
def _handle_command_response (self , report_bytes ):
868
876
(report_body , response_values ) = _parse_command_response (report_bytes )
869
- print (
870
- "report id: %x sequence number: %x command: %x command sequence number: %x response sequence number: %x"
871
- % report_body
872
- )
873
- report_id , sequence_number , command , command_sequence_number = report_body
874
- if command == _ME_CALIBRATE :
877
+
878
+ # report_id, seq_number, command, command_seq_number, response_seq_number) = report_body
879
+ _report_id , _sequence_number , command = report_body
880
+
881
+ # status, accel_en, gyro_en, mag_en, planar_en, table_en, *_reserved) = response_values
882
+ command_status , * _rest = response_values
883
+
884
+ if command == _ME_CALIBRATE and command_status == 0 :
875
885
self ._me_calibration_started_at = time .monotonic ()
886
+
876
887
if command == _SAVE_DCD :
877
- if response_values [ 0 ] == 0 :
888
+ if command_status == 0 :
878
889
self ._dcd_saved_at = time .monotonic ()
879
890
else :
880
891
raise RuntimeError ("Unable to save calibration data" )
@@ -917,9 +928,9 @@ def _process_report(self, report_id, report_bytes):
917
928
activity_classification = _parse_activity_classifier_report (report_bytes )
918
929
self ._readings [BNO_REPORT_ACTIVITY_CLASSIFIER ] = activity_classification
919
930
return
920
-
921
- sensor_data = _parse_sensor_report_data ( report_bytes )
922
-
931
+ sensor_data , accuracy = _parse_sensor_report_data ( report_bytes )
932
+ if report_id == BNO_REPORT_MAGNETOMETER :
933
+ self . _magnetometer_accuracy = accuracy
923
934
# TODO: FIXME; Sensor reports are batched in a LIFO which means that multiple reports
924
935
# for the same type will end with the oldest/last being kept and the other
925
936
# newer reports thrown away
@@ -965,7 +976,7 @@ def enable_feature(self, feature_id):
965
976
start_time = time .monotonic () # 1
966
977
967
978
while _elapsed (start_time ) < _FEATURE_ENABLE_TIMEOUT :
968
- self ._process_available_packets ()
979
+ self ._process_available_packets (max_packets = 10 )
969
980
if feature_id in self ._readings :
970
981
return
971
982
raise RuntimeError ("Was not able to enable feature" , feature_id )
@@ -1070,4 +1081,4 @@ def _increment_report_seq(self, report_id):
1070
1081
self ._two_ended_sequence_numbers [report_id ] = (current + 1 ) % 256
1071
1082
1072
1083
def _get_report_seq_id (self , report_id ):
1073
- return self ._two_ended_sequence_numbers [ report_id ]
1084
+ return self ._two_ended_sequence_numbers . get ( report_id , 0 )
0 commit comments