Skip to content

Commit e9bd385

Browse files
Fix sitting motion and remove spasms (#573)
Co-authored-by: Harold <37922636+YukumoHunter@users.noreply.github.com>
1 parent feb6e94 commit e9bd385

17 files changed

Lines changed: 248 additions & 216 deletions

File tree

deploy/config/walking_engine.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ torso_offset = 0.015
2828
# wear out faster, but the robot will be more stable.
2929
walking_leg_stiffness = 0.8
3030

31+
# The stiffness value used for the leg joints whilst the robot is standing
32+
# higher means the robot's joints will wear out faster, but the robot will be more stable.
33+
standing_leg_stiffness = 0.8
34+
3135
# The stiffness value used for the leg joints while sitting, higher means the robot's joints will
3236
# wear out faster, but the robot will be more stable.
3337
#
@@ -81,7 +85,7 @@ max_sitting_hip_height = 0.145
8185
reached_requested_threshold = 0.001
8286

8387
# Smoothing parameter for the exponential interpolation applied to the hip height.
84-
height_adjustment_smoothing = 0.1
88+
height_adjustment_smoothing = 0.075
8589

8690
# Threshold between two hip height values, when exceeded the values are considered different.
8791
change_threshold = 0.003
@@ -110,10 +114,10 @@ filtered_gyro_y_multiplier = 0.05
110114
# Phase shift for foot leveling drop-off.
111115
#
112116
# Higher values mean the swing foot is leveled for longer.
113-
phase_shift = 0.8
117+
phase_shift = 0.6
114118

115119
# Decay rate for the foot leveling logistic filter.
116-
decay = 14.0
120+
decay = 15.0
117121

118122
# Maximum allowed difference in leveling between steps.
119123
#
@@ -143,7 +147,7 @@ roll_level_scale = 0.0872665
143147
# Multiplier for roll corrections.
144148
#
145149
# Adjusts the strength of leveling for roll adjustments in either direction.
146-
roll_level_factor = 0.5
150+
roll_level_factor = 0.8
147151

148152
# This section contains parameters for the foot support while walking.
149153
[foot_support]
Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
use bevy::prelude::*;
22

3-
use nidhogg::types::{ArmJoints, FillExt, HeadJoints, JointArray, LegJoints};
4-
53
use crate::{
64
behavior::engine::{in_behavior, Behavior, BehaviorState},
7-
motion::walking_engine::{step_context::StepContext, StandingHeight},
8-
nao::{NaoManager, Priority, RobotInfo},
5+
kinematics::Kinematics,
6+
motion::walking_engine::{config::WalkingEngineConfig, step_context::StepContext},
97
};
108

11-
const DEFAULT_PASSIVE_STIFFNESS: f32 = 0.8;
12-
// This should run with priority over the walking engine.
13-
const DEFAULT_PASSIVE_PRIORITY: Priority = Priority::High;
14-
159
pub struct StartUpBehaviorPlugin;
1610

1711
impl Plugin for StartUpBehaviorPlugin {
@@ -29,24 +23,16 @@ impl Behavior for StartUp {
2923
const STATE: BehaviorState = BehaviorState::StartUp;
3024
}
3125

32-
pub fn startup(
33-
robot_info: Res<RobotInfo>,
26+
fn startup(
3427
mut step_context: ResMut<StepContext>,
35-
mut nao_manager: ResMut<NaoManager>,
28+
config: Res<WalkingEngineConfig>,
29+
kinematics: Res<Kinematics>,
3630
) {
37-
step_context.request_stand_with_height(StandingHeight::MAX);
38-
set_initial_joint_values(&robot_info.initial_joint_positions, &mut nao_manager);
39-
}
31+
let hip_height = kinematics.left_hip_height();
4032

41-
fn set_initial_joint_values(
42-
initial_joint_positions: &JointArray<f32>,
43-
nao_manager: &mut NaoManager,
44-
) {
45-
nao_manager.set_all(
46-
initial_joint_positions.clone(),
47-
HeadJoints::fill(DEFAULT_PASSIVE_STIFFNESS),
48-
ArmJoints::fill(DEFAULT_PASSIVE_STIFFNESS),
49-
LegJoints::fill(DEFAULT_PASSIVE_STIFFNESS),
50-
DEFAULT_PASSIVE_PRIORITY,
51-
);
33+
if hip_height >= config.hip_height.max_sitting_hip_height {
34+
step_context.request_stand();
35+
} else {
36+
step_context.request_sit();
37+
}
5238
}

yggdrasil/src/behavior/primary_state.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::{
22
core::audio::whistle_detection::Whistle,
33
game_controller::{penalty::PenaltyState, GameControllerMessageEvent},
4+
kinematics::Kinematics,
5+
motion::walking_engine::config::WalkingEngineConfig,
46
nao::{NaoManager, Priority},
57
sensor::button::{ChestButton, HeadButtons},
68
vision::referee::{
@@ -34,8 +36,7 @@ pub struct PrimaryStatePlugin;
3436

3537
impl Plugin for PrimaryStatePlugin {
3638
fn build(&self, app: &mut App) {
37-
app.insert_resource(PrimaryState::Sitting);
38-
39+
app.add_systems(PostStartup, init_primary_state);
3940
app.add_systems(
4041
Update,
4142
(update_gamecontroller_message, update_primary_state).chain(),
@@ -69,6 +70,20 @@ pub enum PrimaryState {
6970
Calibration,
7071
}
7172

73+
fn init_primary_state(
74+
mut commands: Commands,
75+
config: Res<WalkingEngineConfig>,
76+
kinematics: Res<Kinematics>,
77+
) {
78+
let hip_height = kinematics.left_hip_height();
79+
80+
if hip_height >= config.hip_height.max_sitting_hip_height {
81+
commands.insert_resource(PrimaryState::Initial);
82+
} else {
83+
commands.insert_resource(PrimaryState::Sitting);
84+
}
85+
}
86+
7287
fn update_gamecontroller_message(
7388
mut commands: Commands,
7489
mut events: EventReader<GameControllerMessageEvent>,

yggdrasil/src/core/control/mod.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,6 @@ impl Plugin for ControlPlugin {
2424
fn build(&self, app: &mut App) {
2525
app.add_systems(Startup, setup.after(init_rerun))
2626
.add_plugins((ControlReceivePlugin, ControlTransmitPlugin));
27-
// .add_systems(
28-
// Update,
29-
// (handle_notify_on_connection, send_on_connection)
30-
// .chain()
31-
// .run_if(resource_exists::<ViewerMessageReceiver>),
32-
// )
33-
// .add_systems(
34-
// Update,
35-
// (
36-
// handle_viewer_message,
37-
// (
38-
// (
39-
// handle_viewer_control_message,
40-
// update_debug_systems_for_clients,
41-
// )
42-
// .chain(),
43-
// handle_viewer_game_controller_message,
44-
// ),
45-
// )
46-
// .chain()
47-
// .run_if(resource_exists::<ViewerMessageReceiver>),
48-
// );
4927
}
5028
}
5129

yggdrasil/src/core/control/transmit.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ impl Plugin for ControlTransmitPlugin {
3434
)
3535
.add_systems(
3636
Update,
37-
update_debug_systems_for_clients.after(handle_viewer_control_message),
37+
update_debug_systems_for_clients
38+
.after(handle_viewer_control_message)
39+
.run_if(resource_exists::<ControlAppHandle>),
3840
);
3941
}
4042
}

yggdrasil/src/kinematics/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,11 @@ where
170170
lift,
171171
_side,
172172
} = self;
173-
let foot_translation =
174-
na::Isometry3::translation(forward - torso_offset, *left, -hip_height + lift);
173+
let foot_translation = na::Isometry3::translation(
174+
forward - torso_offset,
175+
*left,
176+
-(hip_height + dimensions::ANKLE_TO_SOLE.z) + lift, // foot translation is computed from the ankle
177+
);
175178
let rotation = Side::foot_rotation(*turn);
176179

177180
Side::robot_to_pelvis() * foot_translation * rotation
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use bevy::prelude::*;
2+
use nidhogg::{types::JointArray, NaoControlMessage, NaoState};
3+
4+
use crate::{nao::CycleTime, prelude::PreWrite};
5+
6+
const MIN_CURRENT: f32 = 0.09;
7+
const MAX_CURRENT: f32 = 0.12;
8+
9+
/// Joint position encoders have a resolution of 1/4096, but we apply a smaller
10+
/// incremental adjustment of 0.01/4096, scaled by cycle time.
11+
///
12+
/// During longer cycles, smaller adjustments are enough, as the motor controllers run as part of HAL, not yggdrasil.
13+
const REDUCTION: f32 = 0.01 / 4096.0;
14+
15+
pub struct EnergyOptimizerPlugin;
16+
17+
impl Plugin for EnergyOptimizerPlugin {
18+
fn build(&self, app: &mut App) {
19+
app.init_resource::<JointCurrentOptimizer>();
20+
app.add_systems(
21+
PreWrite,
22+
optimize_joint_currents
23+
.after(crate::nao::finalize)
24+
.run_if(should_optimize_joint_current),
25+
);
26+
}
27+
}
28+
29+
#[derive(Debug, Resource, Default)]
30+
pub struct JointCurrentOptimizer {
31+
enabled: bool,
32+
has_reach_minimum_current: bool,
33+
joint_offsets: JointArray<f32>,
34+
}
35+
36+
/// Run condition that returns `true` when the [`JointCurrentOptimizer`] is enabled.
37+
fn should_optimize_joint_current(state: Res<JointCurrentOptimizer>) -> bool {
38+
state.enabled
39+
}
40+
41+
/// Extension trait for toggling joint energy optimization.
42+
pub trait EnergyOptimizerExt<'w, 's> {
43+
/// Enables joint current optimization, using [`JointCurrentOptimizer`].
44+
fn optimize_joint_currents(&mut self);
45+
46+
/// Resets the [`JointCurrentOptimizer`] state.
47+
fn reset_joint_current_optimizer(&mut self);
48+
}
49+
50+
impl<'w, 's> EnergyOptimizerExt<'w, 's> for Commands<'w, 's> {
51+
fn optimize_joint_currents(&mut self) {
52+
self.queue(|world: &mut World| {
53+
world.resource_mut::<JointCurrentOptimizer>().enabled = true;
54+
});
55+
}
56+
57+
fn reset_joint_current_optimizer(&mut self) {
58+
self.queue(|world: &mut World| {
59+
world.init_resource::<JointCurrentOptimizer>();
60+
});
61+
}
62+
}
63+
64+
/// System that resets the joint current optimizer state.
65+
pub fn reset_joint_current_optimizer(mut state: ResMut<JointCurrentOptimizer>) {
66+
*state = JointCurrentOptimizer::default();
67+
}
68+
69+
/// System that optimises the requested joint positions based on the maximum current.
70+
///
71+
/// Based on the implementation as described in the Berlin United 2019 Tech Report.
72+
fn optimize_joint_currents(
73+
nao_state: Res<NaoState>,
74+
mut control_msg: ResMut<NaoControlMessage>,
75+
mut state: ResMut<JointCurrentOptimizer>,
76+
cycle_time: Res<CycleTime>,
77+
) {
78+
let (joint_idx, max_current) = nao_state
79+
.current
80+
.as_array_ref()
81+
.into_iter()
82+
.enumerate()
83+
.max_by(|(_, a), (_, b)| a.total_cmp(b))
84+
.unwrap();
85+
86+
state.has_reach_minimum_current = if *max_current < MIN_CURRENT {
87+
true
88+
} else if *max_current > MAX_CURRENT {
89+
false
90+
} else {
91+
state.has_reach_minimum_current
92+
};
93+
94+
if !state.has_reach_minimum_current {
95+
let max_adjustment = REDUCTION / cycle_time.duration.as_secs_f32();
96+
97+
if let Some(joint_offset) = state.joint_offsets.get_mut(joint_idx) {
98+
let requested_joints = control_msg.position.as_array_ref();
99+
let measured_joints = nao_state.position.as_array_ref();
100+
101+
*joint_offset += (requested_joints[joint_idx] - measured_joints[joint_idx])
102+
.clamp(-max_adjustment, max_adjustment);
103+
}
104+
}
105+
106+
control_msg.position = control_msg
107+
.position
108+
.clone()
109+
.zip(state.joint_offsets.clone())
110+
.map(|(position, offset)| position + offset);
111+
112+
// reset the enabled state, so it can be enabled again next cycle if needed.
113+
state.enabled = false;
114+
}

yggdrasil/src/motion/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use bevy::app::PluginGroupBuilder;
22
use bevy::prelude::*;
33

4+
pub mod energy_optimizer;
45
pub mod keyframe;
56
pub mod path_finding;
67
pub mod step_planner;
7-
88
pub mod walking_engine;
99

1010
/// Plugin group containing all plugins related to robot motion.
@@ -15,6 +15,7 @@ impl PluginGroup for MotionPlugins {
1515
PluginGroupBuilder::start::<Self>()
1616
.add(keyframe::KeyframePlugin)
1717
.add(step_planner::StepPlannerPlugin)
18+
.add(energy_optimizer::EnergyOptimizerPlugin)
1819
.add(walking_engine::WalkingEnginePlugin)
1920
}
2021
}

yggdrasil/src/motion/walking_engine/config.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,15 @@ pub struct WalkingEngineConfig {
108108
/// Negative values will make the robot lean backwards while walking.
109109
pub torso_offset: f32,
110110

111-
/// The stiffness value used for the leg joints, higher means the robot's joints will
112-
/// wear out faster, but the robot will be more stable.
111+
/// The stiffness value used for the leg joints whilst the robot is walking
112+
/// higher means the robot's joints will wear out faster, but the robot will be more stable.
113113
pub walking_leg_stiffness: f32,
114114

115-
/// The stiffness value used for the leg joints while walking, higher means the robot's joints will
115+
/// The stiffness value used for the leg joints whilst the robot is standing
116+
/// higher means the robot's joints will wear out faster, but the robot will be more stable.
117+
pub standing_leg_stiffness: f32,
118+
119+
/// The stiffness value used for the leg joints while sitting, higher means the robot's joints will
116120
/// wear out faster, but the robot will be more stable.
117121
///
118122
/// Negative values will turn the motors off completely, sacrificing all stability.

0 commit comments

Comments
 (0)