77import commands2
88import commands2 .button
99import commands2 .cmd
10- from commands2 .sysid import SysIdRoutine
10+ # from commands2.sysid import SysIdRoutine
1111from generated .tuner_constants import TunerConstants
1212from telemetry import Telemetry
1313
14- from phoenix6 import swerve , SignalLogger
14+ from phoenix6 import swerve # , SignalLogger
1515from wpimath .units import rotationsToRadians
1616from lifter import Lifter # Import the Lifter class
1717import wpilib
1818import logging
19-
2019import math
2120
2221# Configure logging
2322logging .basicConfig (level = logging .DEBUG )
2423
24+ MAX_SPEED_SCALING = 0.35
25+ DEAD_BAND = 0.1
26+ ELEVATOR_MOTOR_ID_1 = 20
27+ ELEVATOR_MOTOR_ID_2 = 16
28+
29+ INTAKE_MOTOR_ID_TOP = 18
30+ INTAKE_MOTOR_ID_BOTTOM = 22
2531
2632class RobotContainer :
2733 """
@@ -33,14 +39,14 @@ class RobotContainer:
3339
3440 def __init__ (self ) -> None :
3541 self ._max_speed = (
36- TunerConstants .speed_at_12_volts * .35
42+ TunerConstants .speed_at_12_volts * MAX_SPEED_SCALING
3743 ) # speed_at_12_volts desired top speed
3844 self ._max_angular_rate = rotationsToRadians (
3945 TunerConstants .angular_at_12_volts * .1
4046 )
4147
4248 # Setting up bindings for necessary control of the swerve drive platform
43- self ._deadband = 0.1 # The input deadband
49+ self ._deadband = DEAD_BAND # The input deadband
4450 self ._exponent = 3.0 # Exponential factor (try 2, 2.5, or 3)
4551
4652 self ._drive = (
@@ -61,13 +67,32 @@ def __init__(self) -> None:
6167 self .drivetrain = TunerConstants .create_drivetrain ()
6268
6369 # Initialize the elevator with motor IDs
64- self .elevator = Lifter (20 , 16 )
70+ self .elevator = Lifter (ELEVATOR_MOTOR_ID_1 , ELEVATOR_MOTOR_ID_2 )
6571 # Initialize the intake with motor IDs
66- self .intake = Lifter (18 , 22 )
67- # making it closer to 1 will make the decay slower and smoother.
68-
72+ self .intake = Lifter (INTAKE_MOTOR_ID_TOP , INTAKE_MOTOR_ID_BOTTOM )
73+
6974 # Setup telemetry
70- self ._registerTelemetery ()
75+ self ._registerTelemetry ()
76+
77+ def calculateJoystick (self ) -> tuple [float , float ]:
78+ x0 , y0 = self ._joystick .getLeftX (), self ._joystick .getLeftY ()
79+ magnitude = self .applyExponential (math .hypot (x0 , y0 ), self ._deadband , self ._exponent ) * self ._max_speed
80+ theta = math .atan2 (y0 , x0 )
81+
82+ x1 = magnitude * math .cos (theta )
83+ y1 = magnitude * math .sin (theta )
84+
85+ return x1 , y1
86+
87+ def applyRequest (self ) -> swerve .requests .SwerveRequest :
88+ (new_vx , new_vy ) = self .calculateJoystick ()
89+
90+ return (self ._drive .with_velocity_x (self ._driveMultiplier * new_vy # Drive left with negative X (left)
91+ ) .with_velocity_y (self ._driveMultiplier * new_vx ) # Drive forward with negative Y (forward)
92+ .with_rotational_rate (
93+ self ._driveMultiplier * self .applyExponential (self ._joystick .getRightX (), self ._deadband , self ._exponent ) * self ._max_angular_rate
94+ )) # Drive counterclockwise with negative X (left)
95+
7196
7297 def configureButtonBindings (self ) -> None :
7398 """
@@ -76,36 +101,14 @@ def configureButtonBindings(self) -> None:
76101 if not hasattr (self , '_joystick' ) or self ._joystick is None :
77102 self ._joystick = commands2 .button .CommandXboxController (0 )
78103
104+
79105 # Cache the multiplier
80106 self ._driveMultiplier = - 1.0 if self .isRedAlliance () else 1.0
81-
82- def calculateJoystick ():
83- x0 = self ._joystick .getLeftX ()
84- y0 = self ._joystick .getLeftY ()
85-
86- mag = self .apply_exponential (math .sqrt ((x0 * x0 ) + (y0 * y0 )), self ._deadband , self ._exponent ) * self ._max_speed
87- theta = math .atan2 (y0 , x0 )
88-
89- x1 = mag * math .cos (theta )
90- y1 = mag * math .sin (theta )
91-
92- print ('0: %f, %f 1: %f %f' % (x0 , y0 , x1 , y1 ))
93-
94- return (x1 , y1 )
95-
96- def applyRequest ():
97- (new_vx , new_vy ) = calculateJoystick ()
98-
99- return (self ._drive .with_velocity_x (self ._driveMultiplier * new_vy ) # Drive forward with negative Y (forward)
100- .with_velocity_y (self ._driveMultiplier * new_vx ) # Drive left with negative X (left)
101- .with_rotational_rate (
102- self ._driveMultiplier * self .apply_exponential (self ._joystick .getRightX (), self ._deadband , self ._exponent ) * self ._max_angular_rate
103- )) # Drive counterclockwise with negative X (left)
104-
107+
105108 # Note that X is defined as forward according to WPILib convention,
106109 # and Y is defined as to the left according to WPILib convention.
107- self .drivetrain .setDefaultCommand (self .drivetrain .apply_request (applyRequest ))
108- # reset the field-centric heading on left bumper press
110+ self .drivetrain .setDefaultCommand (self .drivetrain .apply_request (self . applyRequest ))
111+ # reset the field-centric heading on x button press
109112 self ._joystick .x ().onTrue (
110113 self .drivetrain .runOnce (lambda : self .resetHeading ())
111114 )
@@ -133,7 +136,7 @@ def applyRequest():
133136 lambda : self .intake .stop ()
134137 ))
135138
136- def resetHeading (self ):
139+ def resetHeading (self ) -> None :
137140 self .drivetrain .seed_field_centric ()
138141
139142 def getAutonomousCommand (self , selected : str ) -> commands2 .Command :
@@ -143,15 +146,15 @@ def getAutonomousCommand(self, selected: str) -> commands2.Command:
143146 selected ,
144147 is_red_alliance = self .isRedAlliance ())
145148
146- def isRedAlliance (self ):
149+ def isRedAlliance (self ) -> bool :
147150 return wpilib .DriverStation .getAlliance () == wpilib .DriverStation .Alliance .kRed
148151
149- def _registerTelemetery (self ):
152+ def _registerTelemetry (self ) -> None :
150153 self .drivetrain .register_telemetry (
151154 lambda state : self ._logger .telemeterize (state )
152155 )
153156
154- def apply_exponential (self , input : float , deadband : float , exponent : float ) -> float :
157+ def applyExponential (self , input : float , deadband : float , exponent : float ) -> float :
155158 """
156159 Apply an exponential response curve with a deadband on the input
157160 such that the final output goes smoothly from 0 -> ±1 without
@@ -162,19 +165,9 @@ def apply_exponential(self, input: float, deadband: float, exponent: float) -> f
162165 :param exponent: The exponent for the curve (e.g. 2.0 for a squared curve).
163166 :return: A smoothly scaled & exponentiated value in [-1, 1].
164167 """
165- # 1. Apply input deadband (stick within ±deadband => output = 0)
166168 if abs (input ) < deadband :
167169 return 0.0
168170
169- # 2. Preserve sign and work with magnitude
170- sign = 1 if input > 0 else - 1
171- magnitude = abs (input )
172-
173- # 3. Scale from [deadband .. 1] to [0 .. 1]
174- scaled = (magnitude - deadband ) / (1.0 - deadband ) # in [0..1]
175-
176- # 4. Apply exponential. e.g. exponent=2 => x^2, exponent=3 => x^3
177- curved = scaled ** exponent
178-
179- # 5. Reapply sign to restore forward/backward
180- return sign * curved
171+ sign = math .copysign (1 , input ) # Use math.copysign for clarity
172+ scaled = (abs (input ) - deadband ) / (1.0 - deadband )
173+ return sign * math .pow (scaled , exponent )
0 commit comments