Skip to content

Commit bfc62ca

Browse files
committed
refactor(steami_config): Migrate calibrate_magnetometer to steami_screen UI.
1 parent f01b9c5 commit bfc62ca

1 file changed

Lines changed: 104 additions & 94 deletions

File tree

Lines changed: 104 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,150 @@
1-
"""Calibrate the LIS2MDL magnetometer and save to persistent config.
2-
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.
7-
8-
Instructions and a countdown are displayed on the SSD1327 OLED screen.
9-
Press MENU to start the calibration.
10-
"""
1+
"""Calibrate the LIS2MDL magnetometer using steami_screen UI."""
112

123
import gc
134
from time import sleep_ms
145

6+
import ssd1327
157
from daplink_bridge import DaplinkBridge
168
from lis2mdl import LIS2MDL
179
from machine import I2C, SPI, Pin
18-
from ssd1327 import WS_OLED_128X128_SPI
1910
from steami_config import SteamiConfig
11+
from steami_screen import Screen, SSD1327Display
2012

2113
# --- Hardware init ---
2214

2315
i2c = I2C(1)
24-
oled = WS_OLED_128X128_SPI(
25-
SPI(1),
26-
Pin("DATA_COMMAND_DISPLAY"),
27-
Pin("RST_DISPLAY"),
28-
Pin("CS_DISPLAY"),
16+
17+
spi = SPI(1)
18+
dc = Pin("DATA_COMMAND_DISPLAY")
19+
res = Pin("RST_DISPLAY")
20+
cs = Pin("CS_DISPLAY")
21+
22+
display = SSD1327Display(
23+
ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs)
2924
)
25+
26+
screen = Screen(display)
27+
3028
btn_menu = Pin("MENU_BUTTON", Pin.IN, Pin.PULL_UP)
3129

3230
bridge = DaplinkBridge(i2c)
3331
config = SteamiConfig(bridge)
3432
config.load()
33+
3534
mag = LIS2MDL(i2c)
3635
config.apply_magnetometer_calibration(mag)
3736

3837

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-
38+
# --- Helpers ---
6039

6140
def wait_menu():
62-
"""Wait for MENU button press then release."""
6341
while btn_menu.value() == 1:
6442
sleep_ms(10)
6543
while btn_menu.value() == 0:
6644
sleep_ms(10)
6745

6846

69-
# --- Step 1: Display instructions and wait for MENU ---
47+
def show_intro():
48+
screen.clear()
49+
screen.title("COMPAS")
50+
51+
screen.text("Tournez la", at=(22, 38))
52+
screen.text("carte dans", at=(22, 50))
53+
screen.text("toutes les", at=(22, 62))
54+
screen.text("directions", at=(24, 74))
55+
screen.text("Menu=demarrer", at=(10, 90))
56+
57+
screen.show()
58+
59+
60+
def show_progress(remaining):
61+
screen.clear()
62+
screen.title("COMPAS")
63+
64+
screen.text("Acquisition...", at=(12, 44))
65+
screen.value(remaining)
66+
screen.text("Tournez", at=(30, 80))
67+
screen.text("la carte", at=(28, 92))
68+
69+
screen.show()
70+
71+
72+
def show_message(*lines):
73+
screen.clear()
74+
screen.title("COMPAS")
75+
screen.subtitle(*lines)
76+
screen.show()
77+
78+
79+
def show_results(readings):
80+
screen.clear()
81+
screen.title("COMPAS")
82+
83+
screen.text("Resultats:", at=(24, 34))
84+
85+
y = 48
86+
for i, heading in enumerate(readings):
87+
line = "{}: {} deg".format(i + 1, int(heading))
88+
screen.text(line, at=(16, y))
89+
y += 12
90+
91+
screen.text("Termine !", at=(28, 112))
92+
screen.show()
93+
94+
95+
# --- Step 1: Instructions ---
7096

7197
print("=== 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-
])
98+
99+
show_intro()
87100

88101
print("Press MENU to start calibration...")
89102
wait_menu()
90103
print("Starting calibration...\n")
91104

92-
# --- Step 2: Acquisition with countdown ---
105+
106+
# --- Step 2: Acquisition ---
93107

94108
samples = 600
95109
delay = 20
96110
total_sec = (samples * delay) // 1000
111+
97112
xmin = ymin = zmin = 1e9
98113
xmax = ymax = zmax = -1e9
99114

100115
for s in range(samples):
101116
x, y, z = mag.magnetic_field()
117+
102118
xmin = min(xmin, x)
103119
xmax = max(xmax, x)
104120
ymin = min(ymin, y)
105121
ymax = max(ymax, y)
106122
zmin = min(zmin, z)
107123
zmax = max(zmax, z)
124+
108125
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-
])
126+
remaining = total_sec - (s * delay) // 1000
127+
show_progress(remaining)
128+
120129
sleep_ms(delay)
121130

131+
132+
# --- Compute calibration ---
133+
122134
mag.x_off = (xmax + xmin) / 2.0
123135
mag.y_off = (ymax + ymin) / 2.0
124136
mag.z_off = (zmax + zmin) / 2.0
137+
125138
mag.x_scale = (xmax - xmin) / 2.0 or 1.0
126139
mag.y_scale = (ymax - ymin) / 2.0 or 1.0
127140
mag.z_scale = (zmax - zmin) / 2.0 or 1.0
128141

129142
print("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))
134143

135-
# --- Step 3: Save to config zone ---
136144

137-
show(["COMPAS", "", "Sauvegarde..."])
145+
# --- Step 3: Save ---
146+
147+
show_message("Sauvegarde...")
138148

139149
config.set_magnetometer_calibration(
140150
hard_iron_x=mag.x_off,
@@ -144,42 +154,42 @@ def wait_menu():
144154
soft_iron_y=mag.y_scale,
145155
soft_iron_z=mag.z_scale,
146156
)
157+
147158
config.save()
148-
print("Calibration saved to config zone.\n")
149159
sleep_ms(500)
150160

161+
151162
# --- Step 4: Verify ---
152163

153-
show(["COMPAS", "", "Sauvegarde OK", "", "Verification..."])
164+
show_message("Sauvegarde OK", "", "Verification...")
154165

155166
gc.collect()
167+
156168
config2 = SteamiConfig(bridge)
157169
config2.load()
158170

159171
mag2 = LIS2MDL(i2c)
160172
config2.apply_magnetometer_calibration(mag2)
161173

162-
print("Verification (5 heading readings after reload):")
163-
result_lines = ["COMPAS", "", "Resultats:"]
174+
print("Verification (5 readings):")
175+
176+
readings = []
177+
164178
for i in range(5):
165179
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)
180+
readings.append(heading)
181+
182+
screen.clear()
183+
screen.title("COMPAS")
184+
screen.value(int(heading), unit="deg", label="Mesure {}".format(i + 1))
185+
screen.show()
186+
187+
print("Reading {}: {:.1f} deg".format(i + 1, heading))
169188
sleep_ms(500)
170189

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("\nDone! Calibration is stored and will be restored at next boot.")
190+
191+
# --- Done ---
192+
193+
show_results(readings)
194+
195+
print("\nDone! Calibration stored.")

0 commit comments

Comments
 (0)