1+ package frc .utils ;
2+
3+ public class SwerveUtils {
4+
5+ /**
6+ * Steps a value towards a target with a specified step size.
7+ * @param _current The current or starting value. Can be positive or negative.
8+ * @param _target The target value the algorithm will step towards. Can be positive or negative.
9+ * @param _stepsize The maximum step size that can be taken.
10+ * @return The new value for {@code _current} after performing the specified step towards the specified target.
11+ */
12+ public static double StepTowards (double _current , double _target , double _stepsize ) {
13+ if (Math .abs (_current - _target ) <= _stepsize ) {
14+ return _target ;
15+ }
16+ else if (_target < _current ) {
17+ return _current - _stepsize ;
18+ }
19+ else {
20+ return _current + _stepsize ;
21+ }
22+ }
23+
24+ /**
25+ * Steps a value (angle) towards a target (angle) taking the shortest path with a specified step size.
26+ * @param _current The current or starting angle (in radians). Can lie outside the 0 to 2*PI range.
27+ * @param _target The target angle (in radians) the algorithm will step towards. Can lie outside the 0 to 2*PI range.
28+ * @param _stepsize The maximum step size that can be taken (in radians).
29+ * @return The new angle (in radians) for {@code _current} after performing the specified step towards the specified target.
30+ * This value will always lie in the range 0 to 2*PI (exclusive).
31+ */
32+ public static double StepTowardsCircular (double _current , double _target , double _stepsize ) {
33+ _current = WrapAngle (_current );
34+ _target = WrapAngle (_target );
35+
36+ double stepDirection = Math .signum (_target - _current );
37+ double difference = Math .abs (_current - _target );
38+
39+ if (difference <= _stepsize ) {
40+ return _target ;
41+ }
42+ else if (difference > Math .PI ) { //does the system need to wrap over eventually?
43+ //handle the special case where you can reach the target in one step while also wrapping
44+ if (_current + 2 *Math .PI - _target < _stepsize || _target + 2 *Math .PI - _current < _stepsize ) {
45+ return _target ;
46+ }
47+ else {
48+ return WrapAngle (_current - stepDirection * _stepsize ); //this will handle wrapping gracefully
49+ }
50+
51+ }
52+ else {
53+ return _current + stepDirection * _stepsize ;
54+ }
55+ }
56+
57+ /**
58+ * Finds the (unsigned) minimum difference between two angles including calculating across 0.
59+ * @param _angleA An angle (in radians).
60+ * @param _angleB An angle (in radians).
61+ * @return The (unsigned) minimum difference between the two angles (in radians).
62+ */
63+ public static double AngleDifference (double _angleA , double _angleB ) {
64+ double difference = Math .abs (_angleA - _angleB );
65+ return difference > Math .PI ? (2 * Math .PI ) - difference : difference ;
66+ }
67+
68+ /**
69+ * Wraps an angle until it lies within the range from 0 to 2*PI (exclusive).
70+ * @param _angle The angle (in radians) to wrap. Can be positive or negative and can lie multiple wraps outside the output range.
71+ * @return An angle (in radians) from 0 and 2*PI (exclusive).
72+ */
73+ public static double WrapAngle (double _angle ) {
74+ double twoPi = 2 *Math .PI ;
75+
76+ if (_angle == twoPi ) { // Handle this case separately to avoid floating point errors with the floor after the division in the case below
77+ return 0.0 ;
78+ }
79+ else if (_angle > twoPi ) {
80+ return _angle - twoPi *Math .floor (_angle / twoPi );
81+ }
82+ else if (_angle < 0.0 ) {
83+ return _angle + twoPi *(Math .floor ((-_angle ) / twoPi )+1 );
84+ }
85+ else {
86+ return _angle ;
87+ }
88+ }
89+ }
0 commit comments