|
17 | 17 | import mpos.ui |
18 | 18 | import mpos.sensor_manager as SensorManager |
19 | 19 | import mpos.apps |
| 20 | +from mpos.ui.testing import wait_for_render |
20 | 21 |
|
21 | 22 |
|
22 | 23 | class CalibrationState: |
@@ -246,14 +247,106 @@ def handle_quality_error(self, error_msg): |
246 | 247 | self.detail_label.set_text("Check IMU connection and try again") |
247 | 248 |
|
248 | 249 | def start_calibration_process(self): |
249 | | - """Start the calibration process.""" |
250 | | - self.set_state(CalibrationState.CHECKING_STATIONARITY) |
| 250 | + """Start the calibration process. |
251 | 251 |
|
252 | | - # Run in background thread |
253 | | - _thread.stack_size(mpos.apps.good_stack_size()) |
254 | | - _thread.start_new_thread(self.calibration_thread_func, ()) |
| 252 | + Note: Runs in main thread - UI will freeze during calibration (~1 second). |
| 253 | + This avoids threading issues with I2C/sensor access. |
| 254 | + """ |
| 255 | + try: |
| 256 | + print("[CalibrateIMU] === Calibration started ===") |
| 257 | + |
| 258 | + # Step 1: Check stationarity |
| 259 | + print("[CalibrateIMU] Step 1: Checking stationarity...") |
| 260 | + self.set_state(CalibrationState.CHECKING_STATIONARITY) |
| 261 | + wait_for_render() # Let UI update |
| 262 | + |
| 263 | + if self.is_desktop: |
| 264 | + stationarity = {'is_stationary': True, 'message': 'Mock: Stationary'} |
| 265 | + else: |
| 266 | + print("[CalibrateIMU] Calling SensorManager.check_stationarity(samples=30)...") |
| 267 | + stationarity = SensorManager.check_stationarity(samples=30) |
| 268 | + print(f"[CalibrateIMU] Stationarity result: {stationarity}") |
| 269 | + |
| 270 | + if stationarity is None or not stationarity['is_stationary']: |
| 271 | + msg = stationarity['message'] if stationarity else "Stationarity check failed" |
| 272 | + print(f"[CalibrateIMU] Device not stationary: {msg}") |
| 273 | + self.handle_calibration_error( |
| 274 | + f"Device not stationary!\n\n{msg}\n\nPlace on flat surface and try again.") |
| 275 | + return |
| 276 | + |
| 277 | + print("[CalibrateIMU] Device is stationary, proceeding to calibration") |
| 278 | + |
| 279 | + # Step 2: Perform calibration |
| 280 | + print("[CalibrateIMU] Step 2: Performing calibration...") |
| 281 | + self.set_state(CalibrationState.CALIBRATING) |
| 282 | + self.status_label.set_text("Calibrating IMU...\n\nUI will freeze for ~2 seconds\nPlease wait...") |
| 283 | + wait_for_render() # Let UI update before blocking |
| 284 | + |
| 285 | + if self.is_desktop: |
| 286 | + print("[CalibrateIMU] Mock calibration (desktop)") |
| 287 | + time.sleep(2) |
| 288 | + accel_offsets = (0.1, -0.05, 0.15) |
| 289 | + gyro_offsets = (0.2, -0.1, 0.05) |
| 290 | + else: |
| 291 | + # Real calibration - UI will freeze here |
| 292 | + print("[CalibrateIMU] Real calibration (hardware)") |
| 293 | + accel = SensorManager.get_default_sensor(SensorManager.TYPE_ACCELEROMETER) |
| 294 | + gyro = SensorManager.get_default_sensor(SensorManager.TYPE_GYROSCOPE) |
| 295 | + print(f"[CalibrateIMU] Accel sensor: {accel}, Gyro sensor: {gyro}") |
| 296 | + |
| 297 | + if accel: |
| 298 | + print("[CalibrateIMU] Calibrating accelerometer (100 samples)...") |
| 299 | + accel_offsets = SensorManager.calibrate_sensor(accel, samples=100) |
| 300 | + print(f"[CalibrateIMU] Accel offsets: {accel_offsets}") |
| 301 | + else: |
| 302 | + accel_offsets = None |
255 | 303 |
|
256 | | - def calibration_thread_func(self): |
| 304 | + if gyro: |
| 305 | + print("[CalibrateIMU] Calibrating gyroscope (100 samples)...") |
| 306 | + gyro_offsets = SensorManager.calibrate_sensor(gyro, samples=100) |
| 307 | + print(f"[CalibrateIMU] Gyro offsets: {gyro_offsets}") |
| 308 | + else: |
| 309 | + gyro_offsets = None |
| 310 | + |
| 311 | + # Step 3: Verify results |
| 312 | + print("[CalibrateIMU] Step 3: Verifying calibration...") |
| 313 | + self.set_state(CalibrationState.VERIFYING) |
| 314 | + wait_for_render() |
| 315 | + |
| 316 | + if self.is_desktop: |
| 317 | + verify_quality = self.get_mock_quality(good=True) |
| 318 | + else: |
| 319 | + print("[CalibrateIMU] Checking calibration quality (50 samples)...") |
| 320 | + verify_quality = SensorManager.check_calibration_quality(samples=50) |
| 321 | + print(f"[CalibrateIMU] Verification quality: {verify_quality}") |
| 322 | + |
| 323 | + if verify_quality is None: |
| 324 | + print("[CalibrateIMU] Verification failed") |
| 325 | + self.handle_calibration_error("Calibration completed but verification failed") |
| 326 | + return |
| 327 | + |
| 328 | + # Step 4: Show results |
| 329 | + print("[CalibrateIMU] Step 4: Showing results...") |
| 330 | + rating = verify_quality['quality_rating'] |
| 331 | + score = verify_quality['quality_score'] |
| 332 | + |
| 333 | + result_msg = f"Calibration successful!\n\nNew quality: {rating} ({score*100:.0f}%)" |
| 334 | + if accel_offsets: |
| 335 | + result_msg += f"\n\nAccel offsets:\nX:{accel_offsets[0]:.3f} Y:{accel_offsets[1]:.3f} Z:{accel_offsets[2]:.3f}" |
| 336 | + if gyro_offsets: |
| 337 | + result_msg += f"\n\nGyro offsets:\nX:{gyro_offsets[0]:.3f} Y:{gyro_offsets[1]:.3f} Z:{gyro_offsets[2]:.3f}" |
| 338 | + |
| 339 | + print(f"[CalibrateIMU] Calibration complete! Result: {result_msg[:80]}") |
| 340 | + self.show_calibration_complete(result_msg) |
| 341 | + print("[CalibrateIMU] === Calibration finished ===") |
| 342 | + |
| 343 | + except Exception as e: |
| 344 | + print(f"[CalibrateIMU] Calibration error: {e}") |
| 345 | + import sys |
| 346 | + sys.print_exception(e) |
| 347 | + self.handle_calibration_error(str(e)) |
| 348 | + |
| 349 | + def old_calibration_thread_func_UNUSED(self): |
257 | 350 | """Background thread for calibration process.""" |
258 | 351 | try: |
259 | 352 | print("[CalibrateIMU] === Calibration thread started ===") |
@@ -337,16 +430,17 @@ def calibration_thread_func(self): |
337 | 430 | if gyro_offsets: |
338 | 431 | result_msg += f"\n\nGyro offsets:\nX:{gyro_offsets[0]:.3f} Y:{gyro_offsets[1]:.3f} Z:{gyro_offsets[2]:.3f}" |
339 | 432 |
|
340 | | - print(f"[CalibrateIMU] Calibration complete! Result: {result_msg[:80]}") |
| 433 | + print(f"[CalibrateIMU] Calibration compl ete! Result: {result_msg[:80]}") |
341 | 434 | self.update_ui_threadsafe_if_foreground(self.show_calibration_complete, result_msg) |
| 435 | + |
342 | 436 | print("[CalibrateIMU] === Calibration thread finished ===") |
343 | 437 |
|
344 | 438 | except Exception as e: |
345 | 439 | print(f"[CalibrateIMU] Calibration error: {e}") |
346 | 440 | import sys |
347 | 441 | sys.print_exception(e) |
348 | 442 | self.update_ui_threadsafe_if_foreground(self.handle_calibration_error, str(e)) |
349 | | - |
| 443 | + |
350 | 444 | def show_calibration_complete(self, result_msg): |
351 | 445 | """Show calibration completion message.""" |
352 | 446 | self.status_label.set_text(result_msg) |
|
0 commit comments