1+ from pybricks .parameters import Axis
12from pybricks .tools import wait
23
34
@@ -7,3 +8,108 @@ def light_matrix_text_async(display, text, on, off):
78 yield from wait (on )
89 display .off ()
910 yield from wait (off )
11+
12+
13+ def imu_update_heading_correction (hub ):
14+
15+ # Number of turns to confirm the result.
16+ NUMBER_CONFIRM_TURNS = 5
17+
18+ # Maximum speed values before we consider the result invalid.
19+ MAX_XY_SPEED = 50
20+ MAX_Z_SPEED = 800
21+
22+ # Routine to wait on a button, with some extra time to avoid vibration directly after.
23+ def wait_for_click ():
24+ while hub .buttons .pressed ():
25+ wait (1 )
26+ while not hub .buttons .pressed ():
27+ wait (1 )
28+ print ("Processing..." )
29+ while hub .buttons .pressed ():
30+ wait (1 )
31+ wait (1500 )
32+
33+ # Disable stop buttons
34+ hub .system .set_stop_button (None )
35+ print (
36+ "Put the hub on a flat table. Align against a fixed reference like a wall or heavy book. Press hub button when ready."
37+ )
38+
39+ # Wait for fixed reference and store the initial angle value.
40+ wait_for_click ()
41+ while not hub .imu .ready () or not hub .imu .stationary ():
42+ wait (1 )
43+ start_z = hub .imu .rotation (- Axis .Z )
44+
45+ # Wait for a full rotation and get the result.
46+ print (
47+ "Keep the hub flat and slide it to make a full turn clockwise. Put it against the same reference. Press hub button when ready."
48+ )
49+ wait_for_click ()
50+ one_turn = hub .imu .rotation (- Axis .Z ) - start_z
51+
52+ # Require clockwise...
53+ if one_turn < 0 :
54+ raise ValueError ("You turned it the wrong way. Please try again." )
55+
56+ # Sanity check. Should be close to 360.
57+ if not (350 < one_turn < 370 ):
58+ print (one_turn )
59+ raise ValueError (
60+ "The error was more than 10 degrees, which is unexpected. Please try again."
61+ )
62+
63+ # Instruct to make more turns.
64+ print ("So far so good! Now make" , NUMBER_CONFIRM_TURNS , "full clockwise turns." )
65+
66+ for i in range (NUMBER_CONFIRM_TURNS ):
67+
68+ # The rotation target is just under a rotation so we can show the next
69+ # message to keep going in time, avoiding doubts about what to do.
70+ target = one_turn * (i + 2 ) - 10
71+
72+ # Wait until the hub reaches the target.
73+ while hub .imu .rotation (- Axis .Z ) - start_z < target :
74+ wait (1 )
75+
76+ if hub .buttons .pressed ():
77+ raise RuntimeError ("Don't press the button until all turns are complete!" )
78+
79+ if abs (hub .imu .angular_velocity (Axis .Z )) > MAX_Z_SPEED :
80+ raise RuntimeError ("Not so fast! Try again." )
81+
82+ if (
83+ abs (hub .imu .angular_velocity (Axis .X )) + abs (hub .imu .angular_velocity (Axis .Y ))
84+ > MAX_XY_SPEED
85+ ):
86+
87+ raise RuntimeError ("Please keep the hub flat! Try again." )
88+
89+ # Inform user of status.
90+ print ("Completed" , i + 1 , "out of" , NUMBER_CONFIRM_TURNS , "turns. " , end = "" )
91+ if i < NUMBER_CONFIRM_TURNS - 1 :
92+ print ("Keep going!" )
93+ else :
94+ print ("Put it against the same reference. Press hub button when ready." )
95+
96+ # Wait for final confirmation.
97+ wait_for_click ()
98+
99+ # Verify the result.
100+ expected = one_turn * (NUMBER_CONFIRM_TURNS + 1 )
101+ result = hub .imu .rotation (- Axis .Z ) - start_z
102+
103+ if abs (expected - result ) > NUMBER_CONFIRM_TURNS / 2 :
104+ print (
105+ "The" ,
106+ NUMBER_CONFIRM_TURNS ,
107+ "extra turns where different from the first turn. Try again." ,
108+ )
109+ print ("Expected" , expected , "but got" , result )
110+
111+ # Get the final result to save.
112+ average_turn = result / (NUMBER_CONFIRM_TURNS + 1 )
113+ print ("For every 360-degree turn your gyro Z-axis reports:" , average_turn )
114+ hub .imu .settings (heading_correction = average_turn )
115+ print ("Saved! Now the heading() method will report the adjusted value." )
0 commit comments