Skip to content

Commit 05ee8dc

Browse files
committed
fix(ir): inhibit excess motion during/after instant/fast boarding (#10377)
* fix(ir): inhibit excess motion during/after instant boarding * chore: add tests * feat(ir): inhibit during fast boarding too
1 parent 6ee5a8d commit 05ee8dc

File tree

1 file changed

+117
-0
lines changed
  • fbw-common/src/wasm/systems/systems/src/navigation

1 file changed

+117
-0
lines changed

fbw-common/src/wasm/systems/systems/src/navigation/adirs.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::air_conditioning::AdirsToAirCondInterface;
2+
use crate::payload::BoardingRate;
23
use crate::shared::InternationalStandardAtmosphere;
34
use crate::simulation::{InitContext, VariableIdentifier};
45
use crate::{
@@ -249,6 +250,12 @@ struct AdirsSimulatorData {
249250
baro_correction_2_id: VariableIdentifier,
250251
/// Baro correction for fo's side in hPa from the FCU
251252
baro_correction_2: Arinc429Word<f64>,
253+
254+
is_boarding_started_by_user_id: VariableIdentifier,
255+
boarding_rate_id: VariableIdentifier,
256+
257+
is_boarding_started_by_user: bool,
258+
boarding_rate: BoardingRate,
252259
}
253260
impl AdirsSimulatorData {
254261
const MACH: &'static str = "AIRSPEED MACH";
@@ -270,6 +277,8 @@ impl AdirsSimulatorData {
270277
const ANGLE_OF_ATTACK: &'static str = "INCIDENCE ALPHA";
271278
const BARO_CORRECTION_1_HPA: &'static str = "FCU_LEFT_EIS_BARO_HPA";
272279
const BARO_CORRECTION_2_HPA: &'static str = "FCU_RIGHT_EIS_BARO_HPA";
280+
const BOARDING_STARTED_BY_USR: &'static str = "BOARDING_STARTED_BY_USR";
281+
const BOARDING_RATE: &'static str = "BOARDING_RATE";
273282

274283
fn new(context: &mut InitContext) -> Self {
275284
Self {
@@ -330,6 +339,13 @@ impl AdirsSimulatorData {
330339

331340
baro_correction_2_id: context.get_identifier(Self::BARO_CORRECTION_2_HPA.to_owned()),
332341
baro_correction_2: Arinc429Word::new(1013., SignStatus::FailureWarning),
342+
343+
is_boarding_started_by_user_id: context
344+
.get_identifier(Self::BOARDING_STARTED_BY_USR.to_owned()),
345+
boarding_rate_id: context.get_identifier(Self::BOARDING_RATE.to_owned()),
346+
347+
is_boarding_started_by_user: false,
348+
boarding_rate: BoardingRate::Instant,
333349
}
334350
}
335351
}
@@ -359,6 +375,8 @@ impl SimulationElement for AdirsSimulatorData {
359375
self.angle_of_attack = reader.read(&self.angle_of_attack_id);
360376
self.baro_correction_1 = reader.read_arinc429(&self.baro_correction_1_id);
361377
self.baro_correction_2 = reader.read_arinc429(&self.baro_correction_2_id);
378+
self.is_boarding_started_by_user = reader.read(&self.is_boarding_started_by_user_id);
379+
self.boarding_rate = reader.read(&self.boarding_rate_id);
362380
}
363381
}
364382

@@ -1470,6 +1488,7 @@ struct InertialReference {
14701488
extreme_latitude: bool,
14711489
body_velocity_filter: LowPassFilter<Vector2<f64>>,
14721490
excess_motion: bool,
1491+
excess_motion_inhibit_time: Option<Duration>,
14731492
quick_realign_remaining_available_time: Duration,
14741493
alignment_failed: bool,
14751494

@@ -1508,6 +1527,7 @@ struct InertialReference {
15081527
fault_warn_discrete: AdirsDiscreteOutput<bool>,
15091528
}
15101529
impl InertialReference {
1530+
const EXCESS_MOTION_INHIBIT_TIME: Duration = Duration::from_secs(2);
15111531
const FAST_ALIGNMENT_TIME_IN_SECS: f64 = 90.;
15121532
const IR_FAULT_FLASH_DURATION: Duration = Duration::from_millis(50);
15131533
const ATTITUDE_INITIALISATION_DURATION: Duration = Duration::from_secs(28);
@@ -1564,6 +1584,7 @@ impl InertialReference {
15641584
extreme_latitude: false,
15651585
body_velocity_filter: LowPassFilter::new(Self::ALIGNMENT_VELOCITY_TIME_CONSTANT),
15661586
excess_motion: false,
1587+
excess_motion_inhibit_time: None,
15671588
quick_realign_remaining_available_time: Duration::default(),
15681589
alignment_failed: false,
15691590

@@ -1684,6 +1705,15 @@ impl InertialReference {
16841705
simulator_data.latitude.abs().get::<degree>() <= Self::MAX_LATITUDE_FOR_ALIGNMENT
16851706
}
16861707

1708+
fn is_instant_or_fast_boarding_in_progress(simulator_data: AdirsSimulatorData) -> bool {
1709+
match simulator_data.boarding_rate {
1710+
BoardingRate::Instant | BoardingRate::Fast => {
1711+
simulator_data.is_boarding_started_by_user
1712+
}
1713+
_ => false,
1714+
}
1715+
}
1716+
16871717
fn update_remaining_align_duration(
16881718
&mut self,
16891719
context: &UpdateContext,
@@ -1703,6 +1733,14 @@ impl InertialReference {
17031733
.saturating_sub(context.delta());
17041734
}
17051735

1736+
// work around instant/fast boarding upsetting the body velocity and interrupting IR alignment
1737+
if InertialReference::is_instant_or_fast_boarding_in_progress(simulator_data) {
1738+
self.excess_motion_inhibit_time = Some(InertialReference::EXCESS_MOTION_INHIBIT_TIME);
1739+
} else if let Some(excess_motion_inhibit_time) = self.excess_motion_inhibit_time {
1740+
self.excess_motion_inhibit_time =
1741+
excess_motion_inhibit_time.checked_sub(context.delta());
1742+
}
1743+
17061744
// If the align time setting has been changed to instant during alignment,
17071745
// then set remaining time to 0. This allows to implement a "Instant Align" button in the EFB
17081746
// for users who want to align the ADIRS instantly but do not want to change the default
@@ -1713,6 +1751,7 @@ impl InertialReference {
17131751
// If we exceeded the max alignment velocity, the alignment is restarted
17141752
if self.is_aligning()
17151753
&& self.body_velocity_filter.output().max() > Self::MAX_ALIGNMENT_VELOCITY_FPS
1754+
&& self.excess_motion_inhibit_time.is_none()
17161755
{
17171756
self.remaining_align_duration = None;
17181757
self.excess_motion = true;
@@ -2593,6 +2632,18 @@ mod tests {
25932632
self
25942633
}
25952634

2635+
fn boarding_rate_of(mut self, rate: BoardingRate) -> Self {
2636+
self.write_by_name(AdirsSimulatorData::BOARDING_RATE, rate);
2637+
2638+
self
2639+
}
2640+
2641+
fn boarding_started_of(mut self, started: bool) -> Self {
2642+
self.write_by_name(AdirsSimulatorData::BOARDING_STARTED_BY_USR, started);
2643+
2644+
self
2645+
}
2646+
25962647
fn ir_fault_light_illuminated(&mut self, number: usize) -> bool {
25972648
self.read_by_name(&OnOffFaultPushButton::has_fault_id(&format!(
25982649
"ADIRS_IR_{}",
@@ -3356,6 +3407,72 @@ mod tests {
33563407
);
33573408
}
33583409

3410+
#[rstest]
3411+
fn adirs_detects_excess_motion_during_alignment_with_instant_boarding_selected() {
3412+
let mut test_bed = all_adirus_unaligned_test_bed_with()
3413+
.boarding_rate_of(BoardingRate::Instant)
3414+
.body_lateral_velocity_of(Velocity::new::<foot_per_second>(0.1))
3415+
.ir_mode_selector_set_to(1, InertialReferenceMode::Navigation);
3416+
test_bed.run();
3417+
test_bed.run();
3418+
3419+
let maint_word_flags = IrMaintFlags::from_bits(test_bed.maint_word(1).value());
3420+
assert_eq!(
3421+
maint_word_flags.unwrap() & IrMaintFlags::EXCESS_MOTION_ERROR,
3422+
IrMaintFlags::EXCESS_MOTION_ERROR
3423+
);
3424+
}
3425+
3426+
#[rstest]
3427+
fn adirs_detects_excess_motion_during_alignment_with_fast_boarding_selected() {
3428+
let mut test_bed = all_adirus_unaligned_test_bed_with()
3429+
.boarding_rate_of(BoardingRate::Fast)
3430+
.body_lateral_velocity_of(Velocity::new::<foot_per_second>(0.1))
3431+
.ir_mode_selector_set_to(1, InertialReferenceMode::Navigation);
3432+
test_bed.run();
3433+
test_bed.run();
3434+
3435+
let maint_word_flags = IrMaintFlags::from_bits(test_bed.maint_word(1).value());
3436+
assert_eq!(
3437+
maint_word_flags.unwrap() & IrMaintFlags::EXCESS_MOTION_ERROR,
3438+
IrMaintFlags::EXCESS_MOTION_ERROR
3439+
);
3440+
}
3441+
3442+
#[rstest]
3443+
fn adirs_does_not_detect_excess_motion_during_instant_boarding() {
3444+
let mut test_bed = all_adirus_unaligned_test_bed_with()
3445+
.boarding_rate_of(BoardingRate::Instant)
3446+
.boarding_started_of(true)
3447+
.body_lateral_velocity_of(Velocity::new::<foot_per_second>(0.1))
3448+
.ir_mode_selector_set_to(1, InertialReferenceMode::Navigation);
3449+
test_bed.run();
3450+
test_bed.run();
3451+
3452+
let maint_word_flags = IrMaintFlags::from_bits(test_bed.maint_word(1).value());
3453+
assert_eq!(
3454+
maint_word_flags.unwrap() & IrMaintFlags::EXCESS_MOTION_ERROR,
3455+
IrMaintFlags::empty()
3456+
);
3457+
}
3458+
3459+
#[rstest]
3460+
fn adirs_does_not_detect_excess_motion_during_fast_boarding() {
3461+
let mut test_bed = all_adirus_unaligned_test_bed_with()
3462+
.boarding_rate_of(BoardingRate::Fast)
3463+
.boarding_started_of(true)
3464+
.body_lateral_velocity_of(Velocity::new::<foot_per_second>(0.1))
3465+
.ir_mode_selector_set_to(1, InertialReferenceMode::Navigation);
3466+
test_bed.run();
3467+
test_bed.run();
3468+
3469+
let maint_word_flags = IrMaintFlags::from_bits(test_bed.maint_word(1).value());
3470+
assert_eq!(
3471+
maint_word_flags.unwrap() & IrMaintFlags::EXCESS_MOTION_ERROR,
3472+
IrMaintFlags::empty()
3473+
);
3474+
}
3475+
33593476
#[rstest]
33603477
#[case(Angle::new::<degree>(80.))]
33613478
#[case(Angle::new::<degree>(-80.))]

0 commit comments

Comments
 (0)