ego: engine: move some of the system constants out into real const values

This commit is contained in:
2026-02-28 17:15:32 +01:00
parent 54ebbbaea7
commit 315fa633c1

View File

@@ -42,6 +42,24 @@ pub struct BikeStates {
sleep_timer: IdleClock, sleep_timer: IdleClock,
} }
/// Above this speed, the system should consider waking up from sleep mode
const BUMP_SPEED_NOISE_GATE: f32 = 0.1;
/// Above this speed, the system should be fully awake and ready to start moving around with purpose
const WAKEUP_SPEED_NOISE_GATE: f32 = 0.5;
/// Above this average speed, we are considered to be moving around with purpose
const MOVING_SPEED_NOISE_GATE: f32 = 1.0;
/// IMU readings of at least this value are considered valid motion. Below this value, the signal is considered noise while stationary
const MOTION_NOISE_GATE: f32 = 0.8;
/// If the system's calculated speed is increasing or decreasing by this value or more, we are accelerating/decelerating
const ACCELERATION_NOISE_GATE: f32 = 1.0;
/// When we get a heading via GPS, this determines how much weight that value has when blended into the system.
const GPS_HEADING_ALPHA_CORRECTION: f32 = 0.9;
impl Debug for BikeStates { impl Debug for BikeStates {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BikeStates") f.debug_struct("BikeStates")
@@ -69,7 +87,7 @@ impl BikeStates {
Some(coords) => { Some(coords) => {
if self.last_fix != coords { if self.last_fix != coords {
let gps_heading = self.last_fix.angle(&coords); let gps_heading = self.last_fix.angle(&coords);
self.heading.correct(gps_heading as f32, 0.9); self.heading.correct(gps_heading as f32, GPS_HEADING_ALPHA_CORRECTION);
} }
let delta = gps_to_local_meters_haversine(&coords, &gps_pos); let delta = gps_to_local_meters_haversine(&coords, &gps_pos);
@@ -97,7 +115,7 @@ impl BikeStates {
let heading_rotation = Rotation3::from_axis_angle(&Vector3::z_axis(), self.heading.heading()); let heading_rotation = Rotation3::from_axis_angle(&Vector3::z_axis(), self.heading.heading());
let enu_rotated = heading_rotation * body_accel; let enu_rotated = heading_rotation * body_accel;
if body_accel.xy().magnitude() >= 0.8 { if body_accel.xy().magnitude() >= MOTION_NOISE_GATE {
self.kf.predict(enu_rotated.xy(), body_gyro.z, dt); self.kf.predict(enu_rotated.xy(), body_gyro.z, dt);
} else { } else {
// Otherwise, we are standing stationary and should insert accel=0 data into the model // Otherwise, we are standing stationary and should insert accel=0 data into the model
@@ -148,45 +166,43 @@ impl BikeStates {
self.speedo.insert(current_prediction); self.speedo.insert(current_prediction);
// If the model has enough samples to report useful data, we can start analyzing the motion trends // If the model has enough samples to report useful data, we can start analyzing the motion trends
if self.speedo.is_filled() { if self.speedo.is_filled() {
let threshold = 1.0;
// Calculate if the velocity is increasing, decreasing, or mostly the same // Calculate if the velocity is increasing, decreasing, or mostly the same
let trend = self.speedo.data().windows(2).map(|n| { let trend = self.speedo.data().windows(2).map(|n| {
n[1] - n[0] n[1] - n[0]
}).sum::<f32>(); }).sum::<f32>();
// Also grab the average velocity of the last few sample periods // Also grab the average velocity of the last few sample periods
let mean = self.speedo.mean(); let average_speed = self.speedo.mean();
info!("prediction={current_prediction:?} mean={average_speed}");
// Reported velocity is kept only to the first decimal, so we aren't spamming the system with floating point noise // Reported velocity is kept only to the first decimal, so we aren't spamming the system with floating point noise
self.reported_velocity.set((mean * 10.0).trunc() / 10.0); self.reported_velocity.set((average_speed * 10.0).trunc() / 10.0);
if let Some(reported) = self.reported_velocity.read_tripped() { if let Some(reported) = self.reported_velocity.read_tripped() {
predictions.publish(Prediction::Velocity(reported)).await; predictions.publish(Prediction::Velocity(reported)).await;
} }
// We only want to wake up from sleep if our current velocity is obviously intentional, eg not a quick bump // We only want to wake up from sleep if our current velocity is something like a bump
if mean > 0.5 { if average_speed > BUMP_SPEED_NOISE_GATE && self.sleep_timer.wake() {
if self.sleep_timer.wake() {
warn!("Waking from sleep into idle mode"); warn!("Waking from sleep into idle mode");
predictions.publish(Prediction::SetPersonality(Personality::Waking)).await; predictions.publish(Prediction::SetPersonality(Personality::Waking)).await;
predictions.publish(Prediction::SetPersonality(Personality::Parked)).await; predictions.publish(Prediction::SetPersonality(Personality::Parked)).await;
} }
// Here, we additionally release the parking brake if we are currently parked and reading some kind of significant movement // Here, we additionally release the parking brake if we are currently parked and reading substantial movement
if self.parking_timer.wake() { if average_speed > WAKEUP_SPEED_NOISE_GATE && self.parking_timer.wake() {
warn!("Disengaging parking brake"); warn!("Disengaging parking brake");
predictions.publish(Prediction::SetPersonality(Personality::Active)).await; predictions.publish(Prediction::SetPersonality(Personality::Active)).await;
} }
}
// If the total slope is more upwards than not, we are accelerating. // If the total slope is more upwards than not, we are accelerating.
if trend >= threshold { if trend >= ACCELERATION_NOISE_GATE {
self.motion_state.set(MotionState::Accelerating); self.motion_state.set(MotionState::Accelerating);
self.steady_timer.wake(); self.steady_timer.wake();
} else if trend <= -threshold { } else if trend <= -ACCELERATION_NOISE_GATE {
self.steady_timer.wake(); self.steady_timer.wake();
self.motion_state.set(MotionState::Decelerating); self.motion_state.set(MotionState::Decelerating);
} else if self.steady_timer.check() && mean > 1.0 { } else if self.steady_timer.check() && average_speed > MOVING_SPEED_NOISE_GATE {
// If we haven't changed our acceleration for a while, and we still have speed, we are moving at a steady pace // If we haven't changed our acceleration for a while, and we still have speed, we are moving at a steady pace
self.motion_state.set(MotionState::Steady); self.motion_state.set(MotionState::Steady);
} else if current_prediction <= 1.0 && mean <= 1.0 { } else if current_prediction <= 1.0 && average_speed <= MOVING_SPEED_NOISE_GATE {
// If the average and instantaneous speed is rather low, we are probably stationary! // If the average and instantaneous speed is rather low, we are probably stationary!
self.motion_state.set(MotionState::Stationary); self.motion_state.set(MotionState::Stationary);
} }