@ -484,17 +484,19 @@ class GamepadManager : public InputInterface {
}
}
if ( std : : abs ( lx_ ) > dead_zone_ | | std : : abs ( ly_ ) > dead_zone_ ) {
// Bin-smooth the angle to nearest π/6 (30 degree) increment
{
double mag = std : : sqrt ( lx_ * lx_ + ly_ * ly_ ) ;
if ( mag > dead_zone_ ) {
double raw_angle = atan2 ( ly_ , lx_ ) ;
double bin_size = M_PI / 6.0 ;
double binned_angle = std : : round ( raw_angle / bin_size ) * bin_size ;
planner_moving_direction_ = binned_angle - M_PI / 2 + planner_facing_angle_ ;
planner_moving_direction_ = raw_angle - M_PI / 2 + planner_facing_angle_ ;
planner_stick_magnitude_ = std : : min ( static_cast < double > ( mag ) , 1.0 ) ;
if constexpr ( DEBUG_LOGGING ) {
std : : cout < < " [GamepadManager DEBUG] Left stick - Raw angle: " < < raw_angle
< < " rad, Binned angle: " < < binned_angle
< < " rad, Moving direction: " < < planner_moving_direction_ < < " rad " < < std : : endl ;
std : : cout < < " [GamepadManager DEBUG] Left stick - Angle: " < < raw_angle
< < " rad, Magnitude: " < < planner_stick_magnitude_
< < " , Moving direction: " < < planner_moving_direction_ < < " rad " < < std : : endl ;
}
} else {
planner_stick_magnitude_ = 0.0 ;
}
}
}
@ -648,9 +650,9 @@ class GamepadManager : public InputInterface {
double final_speed = planner_use_movement_speed_ ;
double final_height = planner_use_height_ ;
// If left sticks in dead zone, go to idle only for walk/run modes, stay in place for crawl/kneel
if ( std : : abs ( lx_ ) < dead_zone_ & & std : : abs ( ly_ ) < dead_zone_ ) {
// If in WALK or RUN mode, go to IDLE
// Proportional speed from stick magnitude (replaces binary IDLE gate)
if ( planner_stick_magnitude_ < dead_zone_ ) {
// Stick in dead zone — IDLE for walk/run, zero-movement for crawl/kneel
if ( planner_use_movement_mode_ = = static_cast < int > ( LocomotionMode : : WALK ) | |
planner_use_movement_mode_ = = static_cast < int > ( LocomotionMode : : RUN ) ) {
final_mode = static_cast < int > ( LocomotionMode : : IDLE ) ;
@ -663,6 +665,18 @@ class GamepadManager : public InputInterface {
final_speed = 0.0f ;
final_height = 0.4f ;
}
} else if ( planner_use_movement_mode_ = = static_cast < int > ( LocomotionMode : : WALK ) | |
planner_use_movement_mode_ = = static_cast < int > ( LocomotionMode : : RUN ) ) {
// Proportional speed from stick magnitude
double normalized = std : : min ( ( planner_stick_magnitude_ - dead_zone_ ) / ( 1.0 - dead_zone_ ) , 1.0 ) ;
if ( planner_use_movement_mode_ = = static_cast < int > ( LocomotionMode : : WALK ) ) {
final_speed = 0.3 + normalized * ( 1.5 - 0.3 ) ; // 0.3 to 1.5 m/s
} else { // RUN
final_speed = 2.0 + normalized * ( 4.5 - 2.0 ) ; // 2.0 to 4.5 m/s
}
} else if ( planner_use_movement_mode_ = = static_cast < int > ( LocomotionMode : : CRAWLING ) ) {
double normalized = std : : min ( ( planner_stick_magnitude_ - dead_zone_ ) / ( 1.0 - dead_zone_ ) , 1.0 ) ;
final_speed = 0.3 + normalized * ( 1.2 - 0.3 ) ; // 0.3 to 1.2 m/s
}
// Emergency stop resets to idle
@ -759,6 +773,7 @@ class GamepadManager : public InputInterface {
double planner_use_height_ = - 1.0 ; ///< Desired body height (−1 = mode default).
double planner_facing_angle_ = 0.0 ; ///< Accumulated facing direction (radians).
double planner_moving_direction_ = 0.0 ; ///< Current movement direction (radians).
double planner_stick_magnitude_ = 0.0 ; ///< Left stick magnitude (0-1), used for proportional speed.
/// Timestamp when KNEEL_TWO_LEGS mode was entered; used to auto-transition
/// to CRAWLING mode after a 2-second delay.