1- """Calibrate the LIS2MDL magnetometer and save to persistent config .
1+ """Calibrate the LIS2MDL magnetometer using the steami_screen UI .
22
3- This example runs a 3D min/max calibration by collecting samples while
4- the user rotates the board in all directions. The computed hard-iron
5- offsets and soft-iron scale factors are stored in the config zone and
6- survive power cycles.
3+ This example walks through the full calibration flow:
4+
5+ - press MENU to start the calibration,
6+ - rotate the board in all directions while samples are acquired,
7+ - compute hard-iron offsets and soft-iron scale factors,
8+ - save the calibration to persistent SteamiConfig storage,
9+ - reload and verify the calibration survives a fresh config load.
710
811Instructions and a countdown are displayed on the SSD1327 OLED screen.
9- Press MENU to start the calibration.
1012"""
1113
1214import gc
1315from time import sleep_ms
1416
17+ import ssd1327
1518from daplink_bridge import DaplinkBridge
1619from lis2mdl import LIS2MDL
1720from machine import I2C , SPI , Pin
18- from ssd1327 import WS_OLED_128X128_SPI
1921from steami_config import SteamiConfig
22+ from steami_screen import Screen , SSD1327Display
2023
2124# --- Hardware init ---
2225
2326i2c = I2C (1 )
24- oled = WS_OLED_128X128_SPI (
25- SPI (1 ),
26- Pin ("DATA_COMMAND_DISPLAY" ),
27- Pin ("RST_DISPLAY" ),
28- Pin ("CS_DISPLAY" ),
27+
28+ spi = SPI (1 )
29+ dc = Pin ("DATA_COMMAND_DISPLAY" )
30+ res = Pin ("RST_DISPLAY" )
31+ cs = Pin ("CS_DISPLAY" )
32+
33+ display = SSD1327Display (
34+ ssd1327 .WS_OLED_128X128_SPI (spi , dc , res , cs )
2935)
36+
37+ screen = Screen (display )
38+
3039btn_menu = Pin ("MENU_BUTTON" , Pin .IN , Pin .PULL_UP )
3140
3241bridge = DaplinkBridge (i2c )
3342config = SteamiConfig (bridge )
3443config .load ()
44+
3545mag = LIS2MDL (i2c )
3646config .apply_magnetometer_calibration (mag )
3747
3848
39- # --- Helper functions ---
40-
41-
42- def show (lines ):
43- """Display centered text lines on the round OLED screen."""
44- oled .fill (0 )
45- th = len (lines ) * 12
46- ys = max (0 , (128 - th ) // 2 )
47- for i , line in enumerate (lines ):
48- x = max (0 , (128 - len (line ) * 8 ) // 2 )
49- oled .text (line , x , ys + i * 12 , 15 )
50- oled .show ()
51-
52-
53- def draw_degree (x , y , col = 15 ):
54- """Draw a tiny degree symbol (3x3 circle) at pixel position."""
55- oled .pixel (x + 1 , y , col )
56- oled .pixel (x , y + 1 , col )
57- oled .pixel (x + 2 , y + 1 , col )
58- oled .pixel (x + 1 , y + 2 , col )
59-
49+ # --- Helpers ---
6050
6151def wait_menu ():
62- """Wait for MENU button press then release."""
6352 while btn_menu .value () == 1 :
6453 sleep_ms (10 )
6554 while btn_menu .value () == 0 :
6655 sleep_ms (10 )
6756
6857
69- # --- Step 1: Display instructions and wait for MENU ---
58+ def show_intro ():
59+ screen .clear ()
60+ screen .title ("COMPAS" )
61+
62+ screen .subtitle (
63+ "Tournez la" ,
64+ "carte dans" ,
65+ "toutes les" ,
66+ "directions" ,
67+ )
68+ screen .text ("Menu=demarrer" , at = "S" )
69+
70+ screen .show ()
71+
72+
73+ def show_progress (remaining ):
74+ screen .clear ()
75+ screen .title ("COMPAS" )
76+
77+ screen .text ("Acquisition..." , at = (12 , 44 ))
78+ screen .value (remaining , unit = "s" )
79+ screen .subtitle ("Tournez" , "la carte" )
80+
81+ screen .show ()
82+
83+
84+ def show_message (* lines ):
85+ screen .clear ()
86+ screen .title ("COMPAS" )
87+ screen .subtitle (* lines )
88+ screen .show ()
89+
90+
91+ def show_results (readings ):
92+ screen .clear ()
93+ screen .title ("COMPAS" )
94+
95+ screen .text ("Resultats:" , at = (24 , 34 ))
96+
97+ y = 48
98+ for i , heading in enumerate (readings ):
99+ line = "{}: {} deg" .format (i + 1 , int (heading ))
100+ screen .text (line , at = (16 , y ))
101+ y += 12
102+
103+ screen .text ("Termine !" , at = (28 , 112 ))
104+ screen .show ()
105+
106+
107+ # --- Step 1: Instructions ---
70108
71109print ("=== Magnetometer Calibration ===\n " )
72- print ("Current offsets: x={:.1f} y={:.1f} z={:.1f}" .format (
73- mag .x_off , mag .y_off , mag .z_off ))
74- print ("Current scales: x={:.3f} y={:.3f} z={:.3f}\n " .format (
75- mag .x_scale , mag .y_scale , mag .z_scale ))
76-
77- show ([
78- "COMPAS" ,
79- "" ,
80- "Tournez la" ,
81- "carte dans" ,
82- "toutes les" ,
83- "directions" ,
84- "" ,
85- "MENU = demarrer" ,
86- ])
110+
111+ show_intro ()
87112
88113print ("Press MENU to start calibration..." )
89114wait_menu ()
90115print ("Starting calibration...\n " )
91116
92- # --- Step 2: Acquisition with countdown ---
117+
118+ # --- Step 2: Acquisition ---
93119
94120samples = 600
95121delay = 20
96122total_sec = (samples * delay ) // 1000
123+
97124xmin = ymin = zmin = 1e9
98125xmax = ymax = zmax = - 1e9
99126
100127for s in range (samples ):
101128 x , y , z = mag .magnetic_field ()
129+
102130 xmin = min (xmin , x )
103131 xmax = max (xmax , x )
104132 ymin = min (ymin , y )
105133 ymax = max (ymax , y )
106134 zmin = min (zmin , z )
107135 zmax = max (zmax , z )
136+
108137 if s % 50 == 0 :
109- remain = total_sec - (s * delay ) // 1000
110- show ([
111- "COMPAS" ,
112- "" ,
113- "Acquisition..." ,
114- "" ,
115- "Continuez a" ,
116- "tourner" ,
117- "" ,
118- "{} sec" .format (remain ),
119- ])
138+ remaining = total_sec - (s * delay ) // 1000
139+ show_progress (remaining )
140+
120141 sleep_ms (delay )
121142
143+
144+ # --- Compute calibration ---
145+
122146mag .x_off = (xmax + xmin ) / 2.0
123147mag .y_off = (ymax + ymin ) / 2.0
124148mag .z_off = (zmax + zmin ) / 2.0
149+
125150mag .x_scale = (xmax - xmin ) / 2.0 or 1.0
126151mag .y_scale = (ymax - ymin ) / 2.0 or 1.0
127152mag .z_scale = (zmax - zmin ) / 2.0 or 1.0
128153
129154print ("Calibration complete!" )
130- print (" Hard-iron offsets: x={:.1f} y={:.1f} z={:.1f}" .format (
131- mag .x_off , mag .y_off , mag .z_off ))
132- print (" Soft-iron scales: x={:.3f} y={:.3f} z={:.3f}\n " .format (
133- mag .x_scale , mag .y_scale , mag .z_scale ))
134155
135- # --- Step 3: Save to config zone ---
136156
137- show (["COMPAS" , "" , "Sauvegarde..." ])
157+ # --- Step 3: Save ---
158+
159+ show_message ("Sauvegarde..." )
138160
139161config .set_magnetometer_calibration (
140162 hard_iron_x = mag .x_off ,
@@ -144,42 +166,42 @@ def wait_menu():
144166 soft_iron_y = mag .y_scale ,
145167 soft_iron_z = mag .z_scale ,
146168)
169+
147170config .save ()
148- print ("Calibration saved to config zone.\n " )
149171sleep_ms (500 )
150172
173+
151174# --- Step 4: Verify ---
152175
153- show ([ "COMPAS" , "" , " Sauvegarde OK" , "" , "Verification..." ] )
176+ show_message ( " Sauvegarde OK" , "" , "Verification..." )
154177
155178gc .collect ()
179+
156180config2 = SteamiConfig (bridge )
157181config2 .load ()
158182
159183mag2 = LIS2MDL (i2c )
160184config2 .apply_magnetometer_calibration (mag2 )
161185
162- print ("Verification (5 heading readings after reload):" )
163- result_lines = ["COMPAS" , "" , "Resultats:" ]
186+ print ("Verification (5 readings):" )
187+
188+ readings = []
189+
164190for i in range (5 ):
165191 heading = mag2 .heading_flat_only ()
166- line = " {}: cap={:.0f}" .format (i + 1 , heading )
167- print (" Reading {}: heading={:.1f} deg" .format (i + 1 , heading ))
168- result_lines .append (line )
192+ readings .append (heading )
193+
194+ screen .clear ()
195+ screen .title ("COMPAS" )
196+ screen .value (int (heading ), unit = "deg" , label = "Mesure {}" .format (i + 1 ))
197+ screen .show ()
198+
199+ print ("Reading {}: {:.1f} deg" .format (i + 1 , heading ))
169200 sleep_ms (500 )
170201
171- result_lines .append ("" )
172- result_lines .append ("Termine !" )
173-
174- # Draw results with degree symbols
175- oled .fill (0 )
176- th = len (result_lines ) * 12
177- ys = max (0 , (128 - th ) // 2 )
178- for i , line in enumerate (result_lines ):
179- x = max (0 , (128 - len (line ) * 8 ) // 2 )
180- oled .text (line , x , ys + i * 12 , 15 )
181- if "cap=" in line :
182- draw_degree (x + len (line ) * 8 + 1 , ys + i * 12 )
183- oled .show ()
184-
185- print ("\n Done! Calibration is stored and will be restored at next boot." )
202+
203+ # --- Done ---
204+
205+ show_results (readings )
206+
207+ print ("\n Done! Calibration stored." )
0 commit comments