P6b: a new CalibrationBridge owns every calibration call and publishes a `calibration` telemetry group (IMU per-unit and per-side progress, gravity centre, lens, sensor cleaning, RC calibration state and live sticks). Guided full-screen wizards cover compass, IMU, remote controller, gimbal auto calibration, lens, sensor cleaning, centre of gravity, propellers and a vision-sensor guide; gimbal adjust is a horizon-line overlay on the live video. Every start goes through SafetyGate.runMaintenance, and closing mid-run stops what the SDK can stop. Reachable from Settings > Safety > Calibration & maintenance, the Aircraft Status calibrate buttons and the gimbal sheet. Not yet run on an aircraft; the RC key sequence still needs checking per remote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
139 lines
5.3 KiB
Dart
139 lines
5.3 KiB
Dart
import 'package:flutter/foundation.dart';
|
||
|
||
import 'parse.dart';
|
||
|
||
/// One IMU unit's calibration report.
|
||
@immutable
|
||
class ImuUnit {
|
||
const ImuUnit({required this.index, this.state, this.progress, this.gyroscope, this.accelerometer, this.connected});
|
||
|
||
factory ImuUnit.fromMap(Map<String, dynamic> m) => ImuUnit(
|
||
index: asInt(m['index']) ?? 0,
|
||
state: asString(m['state']),
|
||
progress: asInt(m['progress']),
|
||
gyroscope: asString(m['gyroscope']),
|
||
accelerometer: asString(m['accelerometer']),
|
||
connected: asBool(m['connected']),
|
||
);
|
||
|
||
final int index;
|
||
|
||
/// `NONE` / `CALIBRATING` / `SUCCESSFUL` / `FAILED` / `UNKNOWN`.
|
||
final String? state;
|
||
final int? progress; // 0..100
|
||
/// `SensorState` names: `NORMAL_BIAS`, `WARMING_UP`, `IN_MOTION`, `LARGE_BIAS` …
|
||
final String? gyroscope;
|
||
final String? accelerometer;
|
||
final bool? connected;
|
||
}
|
||
|
||
/// The RC wizard's live sticks (−660…660) and dials.
|
||
@immutable
|
||
class RcHardware {
|
||
const RcHardware({this.lx, this.ly, this.rx, this.ry, this.leftDial, this.rightDial});
|
||
|
||
factory RcHardware.fromMap(Map<String, dynamic> m) => RcHardware(
|
||
lx: asInt(m['lx']),
|
||
ly: asInt(m['ly']),
|
||
rx: asInt(m['rx']),
|
||
ry: asInt(m['ry']),
|
||
leftDial: asInt(m['leftDial']),
|
||
rightDial: asInt(m['rightDial']),
|
||
);
|
||
|
||
final int? lx, ly, rx, ry, leftDial, rightDial;
|
||
}
|
||
|
||
/// The calibration and maintenance wizards' state (plan P6b), from the
|
||
/// `calibration` group of the telemetry tick (`CalibrationBridge.kt`). The
|
||
/// compass reports through [AircraftState] and the gimbal through
|
||
/// [GimbalState]; everything else is here.
|
||
class CalibrationState extends ChangeNotifier {
|
||
// ── What the aircraft offers; null = not known yet ─────────────────────────
|
||
int? compassCount;
|
||
int? imuCount;
|
||
bool? gravityCenterSupported;
|
||
bool? propellerSupported;
|
||
bool? lensSupported;
|
||
bool? sensorCleaningSupported;
|
||
bool? rcSupported;
|
||
|
||
// ── IMU ────────────────────────────────────────────────────────────────────
|
||
List<ImuUnit> imuUnits = const <ImuUnit>[];
|
||
|
||
/// The aircraft wants to be turned onto several sides.
|
||
bool? imuMultiSide;
|
||
|
||
/// `CALIBRATING` / `COMPLETED` / `UNKNOWN` for the multi-side sequence.
|
||
String? imuOrientationState;
|
||
|
||
/// `CalibrationOrientation` names: `BOTTOM_DOWN`, `NOSE_DOWN` …
|
||
List<String> imuToCalibrate = const <String>[];
|
||
List<String> imuCalibrated = const <String>[];
|
||
|
||
// ── Gravity centre / lens / sensor cleaning ───────────────────────────────
|
||
/// `NONE` / `CALCULATING` / `SUCCESSFUL` / `FAILED`.
|
||
String? gravityCenterState;
|
||
String? gravityCenterError;
|
||
|
||
/// `NOT_CALIBRATE` / `CALIBRATING` / `CALIBRATED` / `WAITING_FOR_CALIBRATE`.
|
||
String? lensState;
|
||
|
||
/// `IDLE` / `COMPLETED` / `FAIL_NORMAL` / `DATA_ERROR`.
|
||
String? lensResult;
|
||
|
||
/// `SensorCleaningState` name: `IDLE`, `INITIATING`, `WAITING_FOR_LENS_REMOVAL` …
|
||
String? sensorCleaning;
|
||
|
||
// ── Remote controller ─────────────────────────────────────────────────────
|
||
/// `NORMAL` / `MIDDLE` / `LIMITS` / `QUIT` / `TIMEOUT` / `DISCONNECT`.
|
||
String? rcState;
|
||
int? rcSegments;
|
||
|
||
/// Per-axis calibration status (`A`…`H`) as the remote reports it.
|
||
Map<String, Object?> rcAxes = const <String, Object?>{};
|
||
|
||
/// Only while the RC wizard watches the hardware.
|
||
RcHardware? rcHardware;
|
||
|
||
void apply(Map<String, dynamic>? g) {
|
||
final Map<String, dynamic> support = asMap(g?['support']) ?? const <String, dynamic>{};
|
||
compassCount = asInt(support['compassCount']);
|
||
imuCount = asInt(support['imuCount']);
|
||
gravityCenterSupported = asBool(support['gravityCenter']);
|
||
propellerSupported = asBool(support['propeller']);
|
||
lensSupported = asBool(support['lens']);
|
||
sensorCleaningSupported = asBool(support['sensorCleaning']);
|
||
rcSupported = asBool(support['rc']);
|
||
|
||
final Map<String, dynamic>? imu = asMap(g?['imu']);
|
||
imuUnits = <ImuUnit>[for (final Map<String, dynamic> u in asMapList(imu?['units'])) ImuUnit.fromMap(u)];
|
||
imuMultiSide = asBool(imu?['multiSide']);
|
||
imuOrientationState = asString(imu?['orientationState']);
|
||
imuToCalibrate = _strings(imu?['toCalibrate']);
|
||
imuCalibrated = _strings(imu?['calibrated']);
|
||
|
||
final Map<String, dynamic>? gc = asMap(g?['gravityCenter']);
|
||
gravityCenterState = asString(gc?['state']);
|
||
gravityCenterError = asString(gc?['error']);
|
||
|
||
final Map<String, dynamic>? lens = asMap(g?['lens']);
|
||
lensState = asString(lens?['state']);
|
||
lensResult = asString(lens?['result']);
|
||
|
||
sensorCleaning = asString(g?['sensorCleaning']);
|
||
|
||
final Map<String, dynamic>? rc = asMap(g?['rc']);
|
||
rcState = asString(rc?['state']);
|
||
rcSegments = asInt(rc?['segments']);
|
||
rcAxes = asMap(rc?['axes']) ?? const <String, Object?>{};
|
||
final Map<String, dynamic>? hw = asMap(g?['rcHardware']);
|
||
rcHardware = hw == null ? null : RcHardware.fromMap(hw);
|
||
notifyListeners();
|
||
}
|
||
|
||
void clear() => apply(null);
|
||
|
||
static List<String> _strings(Object? v) => v is List ? <String>[for (final Object? e in v) if (e is String) e] : const <String>[];
|
||
}
|