feat(capture): detect the flat pose for targets laid on the ground
This commit is contained in:
@@ -32,7 +32,7 @@ class ParallelismData {
|
|||||||
final TargetPose pose;
|
final TargetPose pose;
|
||||||
|
|
||||||
/// Inclinaison avant/arrière brute en degrés (0° = appareil vertical,
|
/// Inclinaison avant/arrière brute en degrés (0° = appareil vertical,
|
||||||
/// -90° = appareil à plat, caméra vers le sol).
|
/// +90° = appareil à plat, caméra vers le sol).
|
||||||
final double pitchDegrees;
|
final double pitchDegrees;
|
||||||
|
|
||||||
/// Inclinaison gauche/droite en degrés (0° = parfaitement droit).
|
/// Inclinaison gauche/droite en degrés (0° = parfaitement droit).
|
||||||
@@ -41,7 +41,7 @@ class ParallelismData {
|
|||||||
/// Écart de tangage par rapport à la pose détectée.
|
/// Écart de tangage par rapport à la pose détectée.
|
||||||
///
|
///
|
||||||
/// En pose [TargetPose.wall] il vaut exactement [pitchDegrees] ; en pose
|
/// En pose [TargetPose.wall] il vaut exactement [pitchDegrees] ; en pose
|
||||||
/// [TargetPose.ground] il mesure l'écart aux -90° de l'appareil à plat.
|
/// [TargetPose.ground] il mesure l'écart aux +90° de l'appareil à plat.
|
||||||
/// C'est cette valeur qu'il faut afficher : le tangage brut vaudrait -90°
|
/// C'est cette valeur qu'il faut afficher : le tangage brut vaudrait -90°
|
||||||
/// alors que le cadrage est parfait.
|
/// alors que le cadrage est parfait.
|
||||||
final double pitchDeviation;
|
final double pitchDeviation;
|
||||||
@@ -71,9 +71,9 @@ class ParallelismData {
|
|||||||
/// plus proche est retenue automatiquement :
|
/// plus proche est retenue automatiquement :
|
||||||
///
|
///
|
||||||
/// [TargetPose.wall] — cible au mur, appareil vertical (tangage ≈ 0°)
|
/// [TargetPose.wall] — cible au mur, appareil vertical (tangage ≈ 0°)
|
||||||
/// [TargetPose.ground] — cible au sol, appareil à plat (tangage ≈ -90°)
|
/// [TargetPose.ground] — cible au sol, appareil à plat (tangage ≈ +90°)
|
||||||
///
|
///
|
||||||
/// Seul le tangage négatif vaut pour la pose au sol : à plat écran vers le
|
/// Seul le tangage positif vaut pour la pose au sol : à plat écran vers le
|
||||||
/// haut, la caméra vise le plafond et le vert n'aurait aucun sens.
|
/// haut, la caméra vise le plafond et le vert n'aurait aucun sens.
|
||||||
///
|
///
|
||||||
/// Implémente une hystérésis à deux seuils pour éviter le clignotement :
|
/// Implémente une hystérésis à deux seuils pour éviter le clignotement :
|
||||||
@@ -187,10 +187,10 @@ class ParallelismService {
|
|||||||
final double wallPitchDeviation = pitchDeg;
|
final double wallPitchDeviation = pitchDeg;
|
||||||
final double wallWorst = math.max(pitchDeg.abs(), rollDeg.abs());
|
final double wallWorst = math.max(pitchDeg.abs(), rollDeg.abs());
|
||||||
|
|
||||||
// Cible au sol : le tangage idéal est -90° (caméra vers le bas). Écran vers
|
// Cible au sol : le tangage idéal est +90° (caméra vers le bas). Écran vers
|
||||||
// le haut, le tangage vaut +90° et l'écart atteint 180° : la pose au sol ne
|
// le haut, le tangage vaut -90° et l'écart atteint 180° : la pose au sol ne
|
||||||
// peut alors jamais gagner, ce qui est exactement le comportement voulu.
|
// peut alors jamais gagner, ce qui est exactement le comportement voulu.
|
||||||
final double groundPitchDeviation = pitchDeg + 90.0;
|
final double groundPitchDeviation = pitchDeg - 90.0;
|
||||||
final double groundWorst =
|
final double groundWorst =
|
||||||
math.max(groundPitchDeviation.abs(), rollDeg.abs());
|
math.max(groundPitchDeviation.abs(), rollDeg.abs());
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:bully/services/parallelism_service.dart';
|
|||||||
/// Vecteur de gravité mesuré par l'accéléromètre pour une pose donnée.
|
/// Vecteur de gravité mesuré par l'accéléromètre pour une pose donnée.
|
||||||
///
|
///
|
||||||
/// [pitch] et [roll] sont exprimés comme dans le service : le tangage vaut 0°
|
/// [pitch] et [roll] sont exprimés comme dans le service : le tangage vaut 0°
|
||||||
/// appareil vertical et -90° appareil à plat caméra vers le sol.
|
/// appareil vertical et +90° appareil à plat caméra vers le sol.
|
||||||
({double x, double y, double z}) gravity({
|
({double x, double y, double z}) gravity({
|
||||||
double pitch = 0,
|
double pitch = 0,
|
||||||
double roll = 0,
|
double roll = 0,
|
||||||
@@ -68,30 +68,30 @@ void main() {
|
|||||||
|
|
||||||
group('pose cible au sol', () {
|
group('pose cible au sol', () {
|
||||||
test('appareil à plat caméra vers le bas → aligné', () {
|
test('appareil à plat caméra vers le bas → aligné', () {
|
||||||
final data = evaluatePose(ParallelismService(), pitch: -90);
|
final data = evaluatePose(ParallelismService(), pitch: 90);
|
||||||
|
|
||||||
expect(data.pose, TargetPose.ground);
|
expect(data.pose, TargetPose.ground);
|
||||||
expect(data.status, ParallelismStatus.aligned);
|
expect(data.status, ParallelismStatus.aligned);
|
||||||
expect(data.pitchDeviation, closeTo(0, 0.5));
|
expect(data.pitchDeviation, closeTo(0, 0.5));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('l\'écart se mesure par rapport à -90°, pas à 0°', () {
|
test('l\'écart se mesure par rapport à +90°, pas à 0°', () {
|
||||||
final data = evaluatePose(ParallelismService(), pitch: -80);
|
final data = evaluatePose(ParallelismService(), pitch: 80);
|
||||||
|
|
||||||
expect(data.pose, TargetPose.ground);
|
expect(data.pose, TargetPose.ground);
|
||||||
expect(data.pitchDeviation, closeTo(10, 0.5));
|
expect(data.pitchDeviation, closeTo(-10, 0.5));
|
||||||
expect(data.status, ParallelismStatus.aligned);
|
expect(data.status, ParallelismStatus.aligned);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('à plat mais trop incliné → désaligné', () {
|
test('à plat mais trop incliné → désaligné', () {
|
||||||
final data = evaluatePose(ParallelismService(), pitch: -50);
|
final data = evaluatePose(ParallelismService(), pitch: 50);
|
||||||
|
|
||||||
expect(data.status, ParallelismStatus.misaligned);
|
expect(data.status, ParallelismStatus.misaligned);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('à plat écran vers le haut → jamais aligné', () {
|
test('à plat écran vers le haut → jamais aligné', () {
|
||||||
// La caméra vise le plafond : le vert n'aurait aucun sens.
|
// La caméra vise le plafond : le vert n'aurait aucun sens.
|
||||||
final data = evaluatePose(ParallelismService(), pitch: 90);
|
final data = evaluatePose(ParallelismService(), pitch: -90);
|
||||||
|
|
||||||
expect(data.pose, TargetPose.wall);
|
expect(data.pose, TargetPose.wall);
|
||||||
expect(data.status, ParallelismStatus.misaligned);
|
expect(data.status, ParallelismStatus.misaligned);
|
||||||
@@ -116,15 +116,15 @@ void main() {
|
|||||||
|
|
||||||
expect(evaluatePose(service).pose, TargetPose.wall);
|
expect(evaluatePose(service).pose, TargetPose.wall);
|
||||||
// Pile à la frontière des deux poses : on garde celle déjà retenue.
|
// Pile à la frontière des deux poses : on garde celle déjà retenue.
|
||||||
expect(evaluatePose(service, pitch: -45).pose, TargetPose.wall);
|
expect(evaluatePose(service, pitch: 45).pose, TargetPose.wall);
|
||||||
// Franchement du côté du sol : on bascule.
|
// Franchement du côté du sol : on bascule.
|
||||||
expect(evaluatePose(service, pitch: -70).pose, TargetPose.ground);
|
expect(evaluatePose(service, pitch: 70).pose, TargetPose.ground);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('stop() remet la pose et le statut à zéro', () {
|
test('stop() remet la pose et le statut à zéro', () {
|
||||||
final service = ParallelismService();
|
final service = ParallelismService();
|
||||||
|
|
||||||
expect(evaluatePose(service, pitch: -90).pose, TargetPose.ground);
|
expect(evaluatePose(service, pitch: 90).pose, TargetPose.ground);
|
||||||
service.stop();
|
service.stop();
|
||||||
expect(evaluatePose(service).pose, TargetPose.wall);
|
expect(evaluatePose(service).pose, TargetPose.wall);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user