Skip to content

Commit c72088a

Browse files
authored
Fix step context not switching feet properly (#646)
1 parent fed7709 commit c72088a

7 files changed

Lines changed: 52 additions & 27 deletions

File tree

yggdrasil/src/localization/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ fn initialize_pose(
8686
commands.insert_resource(pose);
8787
}
8888

89-
fn motion_is_unsafe(
89+
#[must_use]
90+
pub fn motion_is_unsafe(
9091
keyframe_executor: Res<KeyframeExecutor>,
9192
motion_state: Res<State<Gait>>,
9293
contacts: Res<Contacts>,

yggdrasil/src/localization/odometry.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
44
use serde::{Deserialize, Serialize};
55

66
use crate::{
7-
behavior::{behaviors::Standup, engine::in_behavior},
7+
behavior::engine::BehaviorState,
88
kinematics::{
99
Kinematics,
1010
spaces::{LeftSole, RightSole},
@@ -21,14 +21,15 @@ pub(super) struct OdometryPlugin;
2121

2222
impl Plugin for OdometryPlugin {
2323
fn build(&self, app: &mut App) {
24-
app.init_resource::<Odometry>().add_systems(
25-
PreUpdate,
26-
update_odometry
27-
.run_if(not(in_behavior::<Standup>))
28-
.after(crate::kinematics::update_kinematics)
29-
.after(crate::sensor::orientation::update_orientation)
30-
.after(WalkingEngineSet::Prepare),
31-
);
24+
app.init_resource::<Odometry>()
25+
.add_systems(OnExit(BehaviorState::Standup), reset_odometry)
26+
.add_systems(
27+
PreUpdate,
28+
update_odometry
29+
.after(crate::kinematics::update_kinematics)
30+
.after(crate::sensor::orientation::update_orientation)
31+
.after(WalkingEngineSet::Prepare),
32+
);
3233
}
3334
}
3435

@@ -47,8 +48,6 @@ pub fn update_odometry(
4748
return;
4849
}
4950

50-
// TODO: We should probably reset the odometry in some cases
51-
// See: https://github.com/IntelligentRoboticsLab/yggdrasil/issues/400
5251
odometry.update(
5352
&localization_config.odometry,
5453
&foot_support,
@@ -57,6 +56,16 @@ pub fn update_odometry(
5756
);
5857
}
5958

59+
fn reset_odometry(
60+
mut odometry: ResMut<Odometry>,
61+
orientation: Res<RobotOrientation>,
62+
kinematics: Res<Kinematics>,
63+
) {
64+
odometry.offset_to_last = Isometry2::default();
65+
odometry.last_left_sole_to_right_sole = kinematics.vector::<LeftSole, RightSole>().inner.xy();
66+
odometry.reset_orientation(&orientation);
67+
}
68+
6069
/// Configuration for the odometry.
6170
#[derive(Resource, Debug, Clone, Serialize, Deserialize)]
6271
pub struct OdometryConfig {
@@ -103,7 +112,6 @@ impl Odometry {
103112
Side::Left => left_sole_to_right_sole - self.last_left_sole_to_right_sole,
104113
Side::Right => -left_sole_to_right_sole + self.last_left_sole_to_right_sole,
105114
} / 2.0;
106-
107115
self.last_left_sole_to_right_sole = left_sole_to_right_sole;
108116
let scaled_offset = offset.component_mul(&config.scale_factor);
109117

yggdrasil/src/motion/keyframe/manager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ impl ActiveMotion {
8686
pub fn execute_exit_routine(&self, step_context: &mut StepContext) {
8787
if let Some(ExitRoutine::Standing) = self.motion.settings.exit_routine {
8888
// Since the robot is now standing, we can reset the hip height to the default value.
89-
step_context.request_reset();
89+
step_context.finish_step();
90+
step_context.request_stand();
9091
}
9192
// Add more exit routines here! (along with adding an appropriate enum value)
9293
}

yggdrasil/src/motion/walking_engine/foot_support.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ impl Plugin for FootSupportPlugin {
2424
.run_if(not(in_state(BehaviorState::Standup)))
2525
.in_set(WalkingEngineSet::Prepare),
2626
);
27+
28+
// Reset foot support state when exiting standup to ensure correct foot selection
29+
app.add_systems(
30+
OnExit(BehaviorState::Standup),
31+
reset_foot_support_after_standup,
32+
);
2733
}
2834
}
2935

@@ -89,6 +95,11 @@ impl FootSupportState {
8995
self.support = self.support.opposite();
9096
}
9197

98+
/// Reset the foot support state to default values and re-initialize support side detection.
99+
pub(super) fn reset_after_standup(&mut self) {
100+
*self = Self::default();
101+
}
102+
92103
/// Return `true` if a foot switch has occurred or is predicted in future cycles.
93104
#[must_use]
94105
pub fn predicted_or_switched(&self) -> bool {
@@ -164,3 +175,7 @@ fn update_foot_support(
164175
state.predicted_switch = predicted_switch;
165176
}
166177
}
178+
179+
fn reset_foot_support_after_standup(mut foot_support: ResMut<FootSupportState>) {
180+
foot_support.reset_after_standup();
181+
}

yggdrasil/src/motion/walking_engine/schedule.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use bevy::{ecs::schedule::InternedSystemSet, prelude::*};
22

3-
use crate::kinematics::Kinematics;
43
use crate::prelude::*;
4+
use crate::{behavior::engine::BehaviorState, kinematics::Kinematics};
55

66
use super::{config::WalkingEngineConfig, step::PlannedStep, step_context::StepContext};
77

@@ -65,6 +65,12 @@ impl Plugin for WalkingEngineSchedulePlugin {
6565
PostStartup,
6666
setup_motion_state.in_set(WalkingEngineSet::Finalize),
6767
);
68+
69+
// Dirty hack: Reset the entire step context after standing up.
70+
app.add_systems(
71+
OnExit(BehaviorState::Standup),
72+
setup_motion_state.in_set(WalkingEngineSet::Finalize),
73+
);
6874
}
6975
}
7076

yggdrasil/src/motion/walking_engine/step_context.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::time::{Duration, Instant};
22

33
use crate::{
4+
behavior::{behaviors::Standup, engine::in_behavior},
45
core::debug::{
56
DebugContext,
67
debug_system::{DebugAppExt, SystemToggle},
@@ -38,6 +39,7 @@ impl Plugin for StepContextPlugin {
3839
PreUpdate,
3940
plan_step
4041
.run_if(on_event::<FootSwitchedEvent>)
42+
.run_if(not(in_behavior::<Standup>))
4143
.in_set(WalkingEngineSet::PlanStep)
4244
.after(crate::kinematics::update_kinematics),
4345
);
@@ -80,10 +82,7 @@ impl StepContext {
8082

8183
pub fn request_sit(&mut self) {
8284
self.requested_gait = Gait::Sitting;
83-
self.last_step = PlannedStep {
84-
swing_side: self.last_step.swing_side,
85-
..Default::default()
86-
};
85+
self.last_step = PlannedStep::default();
8786
self.requested_step = Step::default();
8887
}
8988

@@ -157,12 +156,6 @@ impl StepContext {
157156
}
158157
}
159158

160-
pub fn request_reset(&mut self) {
161-
self.requested_reset = true;
162-
self.request_stand();
163-
self.requested_gait = Gait::Standing;
164-
}
165-
166159
pub fn finish_step(&mut self) {
167160
self.last_step = self.planned_step;
168161
}
@@ -208,7 +201,7 @@ impl StepContext {
208201
target,
209202
swing_foot_height: config.base_foot_lift + foot_lift_modifier,
210203
swing_side: next_swing_foot,
211-
}
204+
};
212205
}
213206
}
214207

yggdrasil/src/sensor/foot_bumpers.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::SensorConfig;
22
use super::button::{LeftFootButtons, RightFootButtons};
3+
use crate::localization::motion_is_unsafe;
34
use crate::prelude::*;
45
use crate::{
56
motion::path_finding::Obstacle,
@@ -17,7 +18,7 @@ pub struct FootBumperPlugin;
1718

1819
impl Plugin for FootBumperPlugin {
1920
fn build(&self, app: &mut App) {
20-
app.add_systems(Sensor, obstacle_detection)
21+
app.add_systems(Sensor, obstacle_detection.run_if(not(motion_is_unsafe)))
2122
.init_resource::<ObstacleStateFromBumpers>()
2223
.init_resource::<FootBumperValues>();
2324
}

0 commit comments

Comments
 (0)