-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Documentation and Flowchart for the Walking Engine #1532
Comments
In the attachment is a pdf paper with the finished documentation and a flowchart of the walking engine. \documentclass[a4paper,11pt]{article} \usepackage[utf8]{inputenc} \tikzstyle{module} = [rectangle, minimum width=3.5cm, minimum height=1cm, text centered, draw=black, fill=blue!30] % Define colors for listings % Define language and style for Rust code \lstset{% \title{HULKS Walking Engine Documentation and Flowchart} \begin{document} \maketitle \tableofcontents \section{Introduction} With an increasing demand for robots capable of dynamic and adaptive interactions with their environment, this engine seeks to blend computational efficiency with biomechanical innovation. \section{Modules Overview} \begin{itemize} \newpage \section{Module Descriptions and Interactions} \subsection{Anatomic Constraints Module} \textbf{Purpose:} The Anatomic Constraints module enforces limits on the robot's movements to simulate realistic human anatomical constraints. This consideration is crucial in preventing unnatural posture and movements that could lead to mechanical stress or imbalance. \subsubsection*{Key Components:} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \subsection{Arm Module} \textbf{Purpose:} This module orchestrates arm movements to provide naturalistic human-like swinging motions while adapting to potential obstacles. Arm movements also contribute to balance during dynamic actions such as walking. \subsubsection*{Key Components:} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Feet Module} \textbf{Purpose:} The Feet module is crucial for managing the positioning and trajectory of the robot's feet. It ensures proper placement and movement within various coordinate systems, critical for achieving stable and efficient gaits. \subsubsection*{Key Components:} \begin{lstlisting} \begin{itemize} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \subsection{Foot Leveling Module} \textbf{Purpose:} The Foot Leveling module adjusts the orientation of the robot's feet in real-time to ensure stability, particularly when navigating uneven terrain or responding to balance perturbations. \subsubsection*{Key Components:} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Gyro Balancing Module} \textbf{Purpose:} The Gyro Balancing module uses gyroscope data to dynamically adjust the robot's posture, maintaining balance and stability during movement. This real-time adjustment is crucial for adapting to unexpected shifts in the robot's center of gravity. \subsubsection*{Key Components:} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Kick State Module} \textbf{Purpose:} The Kick State module tracks and controls the execution of kicking maneuvers. It manages the state of the kick process and transitions between different kick steps, ensuring that each phase of the kick is executed accurately. \subsubsection*{Key Components:} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Kick Steps Module} \textbf{Purpose:} The Kick Steps module defines and manages the sequences of steps and joint overrides required to perform kicking actions. Each type of kick is preconfigured with specific movements to ensure precision and effectiveness. \subsubsection*{Key Components:} \begin{lstlisting} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Modes Module} \textbf{Purpose:} The Modes module manages the operational state of the walking engine, coordinating transitions between different behaviors such as standing, walking, and kicking. It serves as a central controller to ensure the system reacts appropriately to command inputs and sensory data. \subsubsection*{Key Components:} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Parameters Module} \textbf{Purpose:} The Parameters module contains configurable settings that influence the behavior and performance of the walking engine. By centralizing these settings, the system ensures consistent behavior adjustments across different modules based on external conditions or testing requirements. \subsubsection*{Key Components:} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \subsection{Step Plan Module} \textbf{Purpose:} The Step Plan module outlines the sequence and trajectory of steps for walking. It integrates environmental data and user parameters to produce a cohesive walking strategy that seeks to optimize speed, stability, and terrain handling. \subsubsection*{Key Components:} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \textbf{Data Flow:} \subsection{Step State Module} \textbf{Purpose:} The Step State module maintains the state of each step being executed by the walking engine. It tracks the status and parameters of steps in real-time, ensuring coordinated movements and transitions. \subsubsection*{Key Components:} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \subsection{Stiffness Module} \textbf{Purpose:} The Stiffness module configures and applies stiffness settings to the robot's joints, optimizing flexibility, responsiveness, and support according to the current mode and operational needs. \subsubsection*{Key Components:} \begin{lstlisting} \subsubsection*{Design Decisions:} \subsubsection*{Interactions:} \section{Flowchart} \begin{itemize}
\end{itemize} \begin{center}
\end{tikzpicture} \end{document} |
@CodeByDamianK can you add this to the documentation? Maybe also make it a bit shorter. You can add images as svgs |
Problem:
Documentation and ideally a flowchart is needed to better understand the walking engine modules/code and how its modules and submodules interact with each other.
Task:
Writing a documentation and creating a flowchart about the walking engine.
Reference: crates/walking_engine/src
Current version of the walking engine modules and code (Copied below for faster access):
Here are the following walking_engine modules:
anatomic_constraints.rs
arm.rs
feet.rs
foot_leveling.rs
gyro_balancing.rs
kick_state.rs
kick_steps.rs
lib.rs
mode.rs
parameters.rs
step_plan.rs
step_state.rs
stiffness.rs
mode
the module mode has also the following sub modules:
catching.rs
kicking.rs
standing.rs
starting.rs
stopping.rs
walking.rs
the following code is in anatomic_constraints.rs :
use types::{step::Step, support_foot::Side};
pub trait AnatomicConstraints {
fn clamp_to_anatomic_constraints(self, support_side: Side, maximum_inside_turn: f32) -> Step;
}
impl AnatomicConstraints for Step {
fn clamp_to_anatomic_constraints(self, support_side: Side, maximum_inside_turn: f32) -> Step {
let sideways_direction = if self.left.is_sign_positive() {
Side::Left
} else {
Side::Right
};
let clamped_left = if sideways_direction == support_side {
0.0
} else {
self.left
};
let turn_direction = if self.turn.is_sign_positive() {
Side::Left
} else {
Side::Right
};
let clamped_turn = if turn_direction == support_side {
self.turn.clamp(-maximum_inside_turn, maximum_inside_turn)
} else {
self.turn
};
Step {
forward: self.forward,
left: clamped_left,
turn: clamped_turn,
}
}
}
the following code is in arm.rs :
use splines::Interpolate as _;
use types::{
joints::{arm::ArmJoints, body::BodyJoints},
motor_commands::MotorCommands,
obstacle_avoiding_arms::ArmCommand,
};
use crate::Context;
pub trait ArmOverrides {
fn override_with_arms(self, cotext: &Context) -> Self;
}
impl ArmOverrides for MotorCommands {
fn override_with_arms(self, context: &Context) -> Self {
let left_swinging_arm = self.positions.left_arm;
let right_swinging_arm = self.positions.right_arm;
}
fn compute_joints(arm_command: &ArmCommand, swinging_arms: ArmJoints) -> ArmJoints {
match arm_command {
ArmCommand::Swing => swinging_arms,
ArmCommand::Activating {
influence,
positions,
} => ArmJoints::lerp(*influence, swinging_arms, *positions),
ArmCommand::Active { positions } => *positions,
}
}
the following code is in feet.rs :
use coordinate_systems::{Robot, Walk};
use kinematics::forward::{left_sole_to_robot, right_sole_to_robot};
use linear_algebra::{point, Isometry3, Orientation3, Pose3, Vector2, Vector3};
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{joints::body::BodyJoints, step::Step, support_foot::Side};
use crate::parameters::Parameters;
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Feet {
pub support_sole: Pose3,
pub swing_sole: Pose3,
}
impl Feet {
pub fn from_joints(
robot_to_walk: Isometry3<Robot, Walk>,
joints: &BodyJoints,
support_side: Side,
) -> Self {
let left_sole = robot_to_walk * left_sole_to_robot(&joints.left_leg).as_pose();
let right_sole = robot_to_walk * right_sole_to_robot(&joints.right_leg).as_pose();
}
the following code is in foot_leveling.rs :
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{joints::body::LowerBodyJoints, support_foot::Side};
use crate::Context;
#[derive(
Debug,
Clone,
Copy,
Serialize,
Deserialize,
Default,
PathSerialize,
PathDeserialize,
PathIntrospect,
)]
pub struct FootLeveling {
pub roll: f32,
pub pitch: f32,
}
impl FootLeveling {
pub fn tick(&mut self, context: &Context, normalized_time_since_start: f32) {
let robot_orientation = *context.robot_orientation;
let robot_to_walk_rotation = context.robot_to_walk.rotation();
let level_orientation = robot_orientation.inner * robot_to_walk_rotation.inner.inverse();
let (level_roll, level_pitch, _) = level_orientation.euler_angles();
let return_factor = ((normalized_time_since_start - 0.5).max(0.0) * 2.0).powi(2);
let target_roll = -level_roll * (1.0 - return_factor);
let target_pitch = -level_pitch * (1.0 - return_factor);
}
pub trait FootLevelingExt {
fn level_swing_foot(self, state: &FootLeveling, support_side: Side) -> Self;
}
impl FootLevelingExt for LowerBodyJoints {
fn level_swing_foot(mut self, state: &FootLeveling, support_side: Side) -> Self {
let swing_leg = match support_side {
Side::Left => &mut self.right_leg,
Side::Right => &mut self.left_leg,
};
swing_leg.ankle_roll += state.roll;
swing_leg.ankle_pitch += state.pitch;
self
}
}
the following code is in gyro_balancing.rs :
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::{body::LowerBodyJoints, leg::LegJoints},
support_foot::Side,
};
use crate::Context;
#[derive(
Debug,
Clone,
Copy,
Serialize,
Deserialize,
Default,
PathSerialize,
PathDeserialize,
PathIntrospect,
)]
pub struct GyroBalancing {
balancing: LegJoints,
}
impl GyroBalancing {
pub fn tick(&mut self, context: &Context) {
let gyro = context.gyro;
let parameters = &context.parameters.gyro_balancing;
let factors = ¶meters.balance_factors;
}
pub trait GyroBalancingExt {
fn balance_using_gyro(self, state: &GyroBalancing, support_side: Side) -> Self;
}
impl GyroBalancingExt for LowerBodyJoints {
fn balance_using_gyro(mut self, state: &GyroBalancing, support_side: Side) -> Self {
let support_leg = match support_side {
Side::Left => &mut self.left_leg,
Side::Right => &mut self.right_leg,
};
*support_leg = *support_leg + state.balancing;
self
}
}
the following code is in kick_state.rs :
use itertools::Itertools;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use splines::Interpolate;
use std::time::Duration;
use types::{
joints::{body::BodyJoints, leg::LegJoints},
motion_command::KickVariant,
support_foot::Side,
};
use crate::kick_steps::{JointOverride, KickStep, KickSteps};
use super::step_state::StepState;
#[derive(
Debug, Copy, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct KickState {
pub variant: KickVariant,
/// the foot that is kicking the ball
pub side: Side,
pub index: usize,
pub strength: f32,
}
impl KickState {
pub fn new(variant: KickVariant, side: Side, strength: f32) -> Self {
KickState {
variant,
side,
index: 0,
strength,
}
}
}
pub trait KickOverride {
fn override_with_kick(self, kick_steps: &KickSteps, kick: &KickState, step: &StepState)
-> Self;
}
impl KickOverride for BodyJoints {
fn override_with_kick(
self,
kick_steps: &KickSteps,
kick: &KickState,
step: &StepState,
) -> Self {
let kick_step = kick_steps.get_step_at(kick.variant, kick.index);
let overrides = compute_kick_overrides(kick_step, step.time_since_start, kick.strength);
match step.plan.support_side {
Side::Left => BodyJoints {
right_leg: self.right_leg + overrides,
..self
},
Side::Right => BodyJoints {
left_leg: self.left_leg + overrides,
..self
},
}
}
}
fn compute_kick_overrides(kick_step: &KickStep, t: Duration, strength: f32) -> LegJoints {
let hip_pitch = kick_step
.hip_pitch_overrides
.as_ref()
.map(|overrides| strength * compute_override(overrides, t))
.unwrap_or(0.0);
let ankle_pitch = kick_step
.ankle_pitch_overrides
.as_ref()
.map(|overrides| strength * compute_override(overrides, t))
.unwrap_or(0.0);
LegJoints {
hip_yaw_pitch: 0.0,
hip_pitch,
hip_roll: 0.0,
knee_pitch: 0.0,
ankle_pitch,
ankle_roll: 0.0,
}
}
fn compute_override(overrides: &[JointOverride], t: Duration) -> f32 {
let Some((start, end)) = overrides
.iter()
.tuple_windows()
.find(|(start, end)| (start.timepoint..end.timepoint).contains(&t))
else {
return 0.0;
};
}
the following code is in kick_steps.rs :
use std::time::Duration;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{motion_command::KickVariant, step::Step};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct JointOverride {
pub value: f32,
pub timepoint: Duration,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct KickStep {
pub base_step: Step,
pub step_duration: Duration,
pub foot_lift_apex: f32,
pub midpoint: f32,
pub hip_pitch_overrides: Option<Vec>,
pub ankle_pitch_overrides: Option<Vec>,
}
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct KickSteps {
pub forward: Vec,
pub turn: Vec,
pub side: Vec,
}
impl KickSteps {
pub fn get_steps(&self, variant: KickVariant) -> &[KickStep] {
match variant {
KickVariant::Forward => &self.forward,
KickVariant::Turn => &self.turn,
KickVariant::Side => &self.side,
}
}
}
the following code is in lib.rs :
use arm::ArmOverrides as _;
use coordinate_systems::{Field, Ground, Robot, Walk};
use kick_steps::KickSteps;
use linear_algebra::{Isometry3, Orientation3, Point2, Point3};
use mode::{
catching::Catching, kicking::Kicking, standing::Standing, starting::Starting,
stopping::Stopping, walking::Walking, Mode,
};
use parameters::Parameters;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
cycle_time::CycleTime, joints::body::BodyJoints, motion_command::KickVariant,
motor_commands::MotorCommands, obstacle_avoiding_arms::ArmCommands,
sensor_data::ForceSensitiveResistors, step::Step, support_foot::Side,
};
mod anatomic_constraints;
mod arm;
pub mod feet;
mod foot_leveling;
mod gyro_balancing;
mod kick_state;
pub mod kick_steps;
pub mod mode;
pub mod parameters;
mod step_plan;
mod step_state;
mod stiffness;
/// # WalkingEngine
/// This node generates foot positions and thus leg angles for the robot to execute a walk.
/// The algorithm to compute the feet trajectories is loosely based on the work of Bernhard Hengst
/// at the team rUNSWift. An explanation of this algorithm can be found in the team's research
/// report from 2014 (http://cgi.cse.unsw.edu.au/~robocup/2014ChampionTeamPaperReports/20140930-Bernhard.Hengst-Walk2014Report.pdf).
pub struct Context<'a> {
pub parameters: &'a Parameters,
pub kick_steps: &'a KickSteps,
pub cycle_time: &'a CycleTime,
pub center_of_mass: &'a Point3,
pub zero_moment_point: &'a Point2,
pub number_of_consecutive_cycles_zero_moment_point_outside_support_polygon: &'a i32,
pub force_sensitive_resistors: &'a ForceSensitiveResistors,
pub robot_orientation: &'a Orientation3,
pub robot_to_ground: Option<&'a Isometry3<Robot, Ground>>,
pub gyro: nalgebra::Vector3,
pub current_joints: BodyJoints,
pub robot_to_walk: Isometry3<Robot, Walk>,
pub obstacle_avoiding_arms: &'a ArmCommands,
}
pub trait WalkTransition {
fn stand(self, context: &Context) -> Mode;
fn walk(self, context: &Context, request: Step) -> Mode;
fn kick(self, context: &Context, variant: KickVariant, side: Side, strength: f32) -> Mode;
}
#[derive(Debug, Clone, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect)]
pub struct Engine {
pub mode: Mode,
}
impl Default for Engine {
fn default() -> Self {
Self {
mode: Mode::Standing(Standing {}),
}
}
}
impl Engine {
pub fn stand(&mut self, context: &Context) {
self.mode = self.mode.stand(context);
}
}
the following code is in mode.rs :
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
use crate::{Context, WalkTransition};
use self::{
catching::Catching, kicking::Kicking, standing::Standing, starting::Starting,
stopping::Stopping, walking::Walking,
};
pub mod catching;
pub mod kicking;
pub mod standing;
pub mod starting;
pub mod stopping;
pub mod walking;
#[derive(
Copy, Clone, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub enum Mode {
Standing(Standing),
Starting(Starting),
Walking(Walking),
Kicking(Kicking),
Stopping(Stopping),
Catching(Catching),
}
impl WalkTransition for Mode {
fn stand(self, context: &Context) -> Mode {
match self {
Self::Standing(standing) => standing.stand(context),
Self::Starting(starting) => starting.stand(context),
Self::Walking(walking) => walking.stand(context),
Self::Kicking(kicking) => kicking.stand(context),
Self::Stopping(stopping) => stopping.stand(context),
Self::Catching(catching) => catching.stand(context),
}
}
}
impl Mode {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
match self {
Self::Standing(standing) => standing.compute_commands(context),
Self::Starting(starting) => starting.compute_commands(context),
Self::Walking(walking) => walking.compute_commands(context),
Self::Kicking(kicking) => kicking.compute_commands(context),
Self::Stopping(stopping) => stopping.compute_commands(context),
Self::Catching(catching) => catching.compute_commands(context),
}
}
}
the following code is in parameters.rs :
use std::time::Duration;
use coordinate_systems::Walk;
use linear_algebra::Vector3;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::{arm::ArmJoints, leg::LegJoints},
step::Step,
};
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Parameters {
pub base: Base,
pub catching_steps: CatchingStepsParameters,
pub gyro_balancing: GyroBalancingParameters,
pub max_forward_acceleration: f32,
pub max_inside_turn: f32,
pub max_step_duration: Duration,
pub max_support_foot_lift_speed: f32,
pub min_step_duration: Duration,
pub sole_pressure_threshold: f32,
pub starting_step: StartingStepParameters,
pub step_midpoint: Step,
pub stiffnesses: Stiffnesses,
pub swinging_arms: SwingingArmsParameters,
pub max_level_delta: f32,
pub max_rotation_speed: f32,
}
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Base {
pub foot_lift_apex: f32,
pub foot_lift_apex_increase: Step,
pub foot_offset_left: Vector3,
pub foot_offset_right: Vector3,
pub step_duration: Duration,
pub step_duration_increase: Step,
pub step_midpoint: f32,
pub torso_offset: f32,
pub torso_tilt: f32,
pub walk_height: f32,
}
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct StartingStepParameters {
pub foot_lift_apex: f32,
pub step_duration: Duration,
}
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Stiffnesses {
pub arm_stiffness: f32,
pub leg_stiffness_walk: f32,
pub leg_stiffness_stand: f32,
}
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct GyroBalancingParameters {
pub balance_factors: LegJoints,
pub low_pass_factor: f32,
pub max_delta: LegJoints,
}
#[derive(
Copy,
Clone,
Debug,
Default,
Deserialize,
Serialize,
PathSerialize,
PathDeserialize,
PathIntrospect,
)]
pub struct CatchingStepsParameters {
pub enabled: bool,
pub catching_step_zero_moment_point_frame_count_threshold: i32,
pub max_adjustment: f32,
pub midpoint: f32,
pub target_overestimation_factor: f32,
pub longitudinal_offset: f32,
pub additional_foot_lift: f32,
}
#[derive(
Clone, Debug, Default, Deserialize, Serialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct SwingingArmsParameters {
pub default_roll: f32,
pub roll_factor: f32,
pub pitch_factor: f32,
pub pull_back_joints: ArmJoints,
pub pull_tight_joints: ArmJoints,
pub pulling_back_duration: Duration,
pub pulling_tight_duration: Duration,
pub torso_tilt_compensation_factor: f32,
}
the following code is in step_plan.rs :
use std::time::Duration;
use coordinate_systems::Walk;
use linear_algebra::Vector2;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{step::Step, support_foot::Side};
use crate::Context;
use super::{anatomic_constraints::AnatomicConstraints, feet::Feet};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct StepPlan {
pub step_duration: Duration,
pub start_feet: Feet,
pub end_feet: Feet,
pub support_side: Side,
pub foot_lift_apex: f32,
pub midpoint: f32,
}
impl StepPlan {
pub fn new_from_request(context: &Context, requested_step: Step, support_side: Side) -> Self {
let parameters = &context.parameters;
let start_feet =
Feet::from_joints(context.robot_to_walk, &context.current_joints, support_side);
}
fn interpolate_midpoint(
swing_foot_travel: Vector2,
target_midpoints: Step,
base_midpoint: f32,
) -> f32 {
match swing_foot_travel.try_normalize(f32::EPSILON) {
Some(travel) => travel.x() * target_midpoints.forward + travel.y() * target_midpoints.left,
None => base_midpoint,
}
}
fn travel_weighting(translation_travel: Vector2, turn_travel: f32, factors: Step) -> f32 {
let translational = nalgebra::vector![
factors.forward * translation_travel.x(),
factors.left * translation_travel.y(),
]
.norm();
let rotational = factors.turn * turn_travel;
translational + rotational
}
the following code is in step_state.rs :
use std::{f32::consts::FRAC_PI_2, time::Duration};
use coordinate_systems::{LeftSole, RightSole, Walk};
use kinematics::inverse::leg_angles;
use linear_algebra::{point, Isometry3, Orientation3, Point3, Pose3, Rotation3};
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use splines::Interpolate;
use types::{
joints::{arm::ArmJoints, body::BodyJoints, leg::LegJoints, mirror::Mirror},
robot_dimensions::RobotDimensions,
support_foot::Side,
};
use crate::{
parameters::{Parameters, SwingingArmsParameters},
Context,
};
use super::{
feet::Feet,
foot_leveling::{FootLeveling, FootLevelingExt},
gyro_balancing::{GyroBalancing, GyroBalancingExt},
step_plan::StepPlan,
};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct StepState {
pub plan: StepPlan,
pub time_since_start: Duration,
pub gyro_balancing: GyroBalancing,
pub foot_leveling: FootLeveling,
}
impl StepState {
pub fn new(plan: StepPlan) -> Self {
StepState {
plan,
time_since_start: Duration::ZERO,
gyro_balancing: Default::default(),
foot_leveling: Default::default(),
}
}
}
fn swinging_arm(
parameters: &SwingingArmsParameters,
same_leg: LegJoints,
opposite_foot_x: f32,
) -> ArmJoints {
let shoulder_roll = parameters.default_roll + parameters.roll_factor * same_leg.hip_roll;
let shoulder_pitch = FRAC_PI_2 - opposite_foot_x * parameters.pitch_factor;
ArmJoints {
shoulder_pitch,
shoulder_roll,
elbow_yaw: 0.0,
elbow_roll: 0.0,
wrist_yaw: -FRAC_PI_2,
hand: 0.0,
}
}
// visualized in desmos: https://www.desmos.com/calculator/kcr3uxqmyw
fn parabolic_return(x: f32, midpoint: f32) -> f32 {
if x < midpoint {
-2.0 / midpoint.powi(3) * x.powi(3) + 3.0 / midpoint.powi(2) * x.powi(2)
} else {
-1.0 / (midpoint - 1.0).powi(3)
* (2.0 * x.powi(3) - 3.0 * (midpoint + 1.0) * x.powi(2) + 6.0 * midpoint * x
- 3.0 * midpoint
+ 1.0)
}
}
fn parabolic_step(x: f32) -> f32 {
if x < 0.5 {
2.0 * x * x
} else {
4.0 * x - 2.0 * x * x - 1.0
}
}
the following code is in stiffness.rs :
use types::{
joints::body::{BodyJoints, LowerBodyJoints, UpperBodyJoints},
motor_commands::MotorCommands,
};
pub trait Stiffness {
fn apply_stiffness(self, legs: f32, arms: f32) -> MotorCommands<BodyJoints>;
}
impl Stiffness for BodyJoints {
fn apply_stiffness(self, legs: f32, arms: f32) -> MotorCommands<BodyJoints> {
let stiffnesses = BodyJoints::from_lower_and_upper(
LowerBodyJoints::fill(legs),
UpperBodyJoints::fill(arms),
);
MotorCommands {
positions: self,
stiffnesses,
}
}
}
the following code is in catching.rs :
use std::time::Duration;
use crate::{
anatomic_constraints::AnatomicConstraints, parameters::Parameters, step_plan::StepPlan,
stiffness::Stiffness as _, Context,
};
use super::{
super::{feet::Feet, step_state::StepState},
stopping::Stopping,
walking::Walking,
Mode, WalkTransition,
};
use coordinate_systems::Ground;
use linear_algebra::Point2;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Catching {
pub step: StepState,
}
impl Catching {
pub fn new(context: &Context, support_side: Side) -> Self {
let parameters = &context.parameters;
}
fn catching_end_feet(
parameters: &Parameters,
zero_moment_point: Point2,
support_side: Side,
) -> Feet {
let target_overestimation_factor = parameters.catching_steps.target_overestimation_factor;
let longitudinal_zero_moment_point_offset = parameters.catching_steps.longitudinal_offset;
let max_adjustment = parameters.catching_steps.max_adjustment;
}
impl WalkTransition for Catching {
fn stand(self, context: &Context) -> Mode {
let current_step = self.step;
if current_step.is_support_switched(context) {
return self.next_step(context);
}
}
impl Catching {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
self.step.compute_joints(context).apply_stiffness(
context.parameters.stiffnesses.leg_stiffness_walk,
context.parameters.stiffnesses.arm_stiffness,
)
}
}
the following code is in kicking.rs :
use std::time::Duration;
use crate::{
feet::Feet,
kick_state::{KickOverride as _, KickState},
step_plan::StepPlan,
step_state::StepState,
stiffness::Stiffness as _,
Context,
};
use super::{stopping::Stopping, walking::Walking, Mode, WalkTransition};
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Kicking {
pub kick: KickState,
pub step: StepState,
}
impl Kicking {
pub fn new(context: &Context, kick: KickState, support_side: Side) -> Self {
let start_feet =
Feet::from_joints(context.robot_to_walk, &context.current_joints, support_side);
}
impl WalkTransition for Kicking {
fn stand(self, context: &Context) -> Mode {
let current_step = self.step;
if current_step.is_support_switched(context)
|| current_step.is_timeouted(context.parameters)
{
return Mode::Stopping(Stopping::new(
context,
current_step.plan.support_side.opposite(),
));
}
}
impl Kicking {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
self.step
.compute_joints(context)
.override_with_kick(context.kick_steps, &self.kick, &self.step)
.apply_stiffness(
context.parameters.stiffnesses.leg_stiffness_walk,
context.parameters.stiffnesses.arm_stiffness,
)
}
}
the following code is in standing.rs :
use std::time::Duration;
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
use crate::{
feet::Feet, step_plan::StepPlan, step_state::StepState, stiffness::Stiffness as _, Context,
WalkTransition,
};
use super::{starting::Starting, Mode};
#[derive(
Default,
Clone,
Copy,
Debug,
Serialize,
Deserialize,
PathSerialize,
PathDeserialize,
PathIntrospect,
)]
pub struct Standing {}
impl WalkTransition for Standing {
fn stand(self, _context: &Context) -> Mode {
Mode::Standing(Standing {})
}
}
impl Standing {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
let feet = Feet::end_from_request(context.parameters, Step::ZERO, Side::Left);
}
the following code is in starting.rs :
use crate::{
kick_state::KickState, step_plan::StepPlan, step_state::StepState, stiffness::Stiffness as _,
Context,
};
use super::{kicking::Kicking, standing::Standing, Mode, WalkTransition, Walking};
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Starting {
pub step: StepState,
}
impl Starting {
pub fn new(context: &Context, support_side: Side) -> Self {
let plan = StepPlan::new_from_request(context, Step::ZERO, support_side);
let step = StepState::new(plan);
Self { step }
}
}
impl WalkTransition for Starting {
fn stand(self, context: &Context) -> Mode {
let current_step = self.step;
if current_step.is_support_switched(context)
|| current_step.is_timeouted(context.parameters)
{
return Mode::Standing(Standing {});
}
}
impl Starting {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
self.step.compute_joints(context).apply_stiffness(
context.parameters.stiffnesses.leg_stiffness_walk,
context.parameters.stiffnesses.arm_stiffness,
)
}
}
the following code is in stopping.rs :
use crate::{
kick_state::KickState, step_plan::StepPlan, step_state::StepState, stiffness::Stiffness as _,
Context,
};
use super::{kicking::Kicking, standing::Standing, walking::Walking, Mode, WalkTransition};
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Stopping {
pub step: StepState,
}
impl Stopping {
pub fn new(context: &Context, support_side: Side) -> Self {
let plan = StepPlan::new_from_request(context, Step::ZERO, support_side);
let step = StepState::new(plan);
Self { step }
}
}
impl WalkTransition for Stopping {
fn stand(self, context: &Context) -> Mode {
let current_step = self.step;
if current_step.is_support_switched(context)
|| current_step.is_timeouted(context.parameters)
{
return Mode::Standing(Standing {});
}
}
impl Stopping {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
self.step.compute_joints(context).apply_stiffness(
context.parameters.stiffnesses.leg_stiffness_walk,
context.parameters.stiffnesses.arm_stiffness,
)
}
}
the following code is in walking.rs :
use super::{catching::Catching, kicking::Kicking, stopping::Stopping, Mode, WalkTransition};
use path_serde::{PathDeserialize, PathIntrospect, PathSerialize};
use serde::{Deserialize, Serialize};
use types::{
joints::body::BodyJoints, motion_command::KickVariant, motor_commands::MotorCommands,
step::Step, support_foot::Side,
};
use crate::{
kick_state::KickState, step_plan::StepPlan, step_state::StepState, stiffness::Stiffness as _,
Context,
};
#[derive(
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
)]
pub struct Walking {
pub step: StepState,
pub requested_step: Step,
}
impl Walking {
pub fn new(
context: &Context,
requested_step: Step,
support_side: Side,
last_requested_step: Step,
) -> Self {
let requested_step = Step {
forward: last_requested_step.forward
+ (requested_step.forward - last_requested_step.forward)
.min(context.parameters.max_forward_acceleration),
left: requested_step.left,
turn: requested_step.turn,
};
let plan = StepPlan::new_from_request(context, requested_step, support_side);
let step = StepState::new(plan);
Self {
step,
requested_step,
}
}
}
impl WalkTransition for Walking {
fn stand(self, context: &Context) -> Mode {
let current_step = self.step;
if current_step.is_support_switched(context)
|| current_step.is_timeouted(context.parameters)
{
return Mode::Stopping(Stopping::new(
context,
current_step.plan.support_side.opposite(),
));
}
}
impl Walking {
pub fn compute_commands(&self, context: &Context) -> MotorCommands {
self.step.compute_joints(context).apply_stiffness(
context.parameters.stiffnesses.leg_stiffness_walk,
context.parameters.stiffnesses.arm_stiffness,
)
}
}
The text was updated successfully, but these errors were encountered: