mirror of
https://github.com/BroncBotz3481/YAGSL
synced 2026-06-19 06:21:40 +00:00
194 lines
7.5 KiB
Java
194 lines
7.5 KiB
Java
package swervelib;
|
|
|
|
import edu.wpi.first.math.controller.PIDController;
|
|
import edu.wpi.first.math.filter.SlewRateLimiter;
|
|
import edu.wpi.first.math.geometry.Translation2d;
|
|
import edu.wpi.first.math.kinematics.ChassisSpeeds;
|
|
import swervelib.parser.SwerveControllerConfiguration;
|
|
|
|
/**
|
|
* Controller class used to convert raw inputs into robot speeds.
|
|
*/
|
|
public class SwerveController
|
|
{
|
|
|
|
/**
|
|
* {@link SwerveControllerConfiguration} object storing data to generate the {@link PIDController} for controlling the
|
|
* robot heading, and deadband for heading joystick.
|
|
*/
|
|
public final SwerveControllerConfiguration config;
|
|
/**
|
|
* PID Controller for the robot heading.
|
|
*/
|
|
private final PIDController thetaController; // TODO: Switch to ProfilePIDController
|
|
/**
|
|
* Last angle as a scalar [-1,1] the robot was set to.
|
|
*/
|
|
public double lastAngleScalar;
|
|
/**
|
|
* {@link SlewRateLimiter} for movement in the X direction in meters/second.
|
|
*/
|
|
public SlewRateLimiter xLimiter = null;
|
|
/**
|
|
* {@link SlewRateLimiter} for movement in the Y direction in meters/second.
|
|
*/
|
|
public SlewRateLimiter yLimiter = null;
|
|
/**
|
|
* {@link SlewRateLimiter} for angular movement in radians/second.
|
|
*/
|
|
public SlewRateLimiter angleLimiter = null;
|
|
|
|
/**
|
|
* Construct the SwerveController object which is used for determining the speeds of the robot based on controller
|
|
* input.
|
|
*
|
|
* @param cfg {@link SwerveControllerConfiguration} containing the PIDF variables for the heading PIDF.
|
|
*/
|
|
public SwerveController(SwerveControllerConfiguration cfg)
|
|
{
|
|
config = cfg;
|
|
thetaController = config.headingPIDF.createPIDController();
|
|
thetaController.enableContinuousInput(-Math.PI, Math.PI);
|
|
lastAngleScalar = 0;
|
|
}
|
|
|
|
/**
|
|
* Helper function to get the {@link Translation2d} of the chassis speeds given the {@link ChassisSpeeds}.
|
|
*
|
|
* @param speeds Chassis speeds.
|
|
* @return {@link Translation2d} of the speed the robot is going in.
|
|
*/
|
|
public static Translation2d getTranslation2d(ChassisSpeeds speeds)
|
|
{
|
|
return new Translation2d(speeds.vxMetersPerSecond, speeds.vyMetersPerSecond);
|
|
}
|
|
|
|
/**
|
|
* Add slew rate limiters to all controls. This prevents the robot from ramping up too much. To disable a
|
|
* {@link SlewRateLimiter} set the desired one to null.
|
|
*
|
|
* @param x The {@link SlewRateLimiter} for the X velocity in meters/second.
|
|
* @param y The {@link SlewRateLimiter} for the Y velocity in meters/second.
|
|
* @param angle The {@link SlewRateLimiter} for the angular velocity in radians/second.
|
|
*/
|
|
public void addSlewRateLimiters(SlewRateLimiter x, SlewRateLimiter y, SlewRateLimiter angle)
|
|
{
|
|
xLimiter = x;
|
|
yLimiter = y;
|
|
angleLimiter = angle;
|
|
}
|
|
|
|
/**
|
|
* Calculate the hypot deadband and check if the joystick is within it.
|
|
*
|
|
* @param x The x value for the joystick in which the deadband should be applied.
|
|
* @param y The y value for the joystick in which the deadband should be applied.
|
|
* @return Whether the values are within the deadband from
|
|
* {@link SwerveControllerConfiguration#angleJoyStickRadiusDeadband}.
|
|
*/
|
|
public boolean withinHypotDeadband(double x, double y)
|
|
{
|
|
return Math.hypot(x, y) < config.angleJoyStickRadiusDeadband;
|
|
}
|
|
|
|
/**
|
|
* Get the chassis speeds based on controller input of 1 joystick and an angle. Cubes the x and y input for smoother
|
|
* motion.
|
|
*
|
|
* @param xInput X joystick input for the robot to move in the X direction.
|
|
* @param yInput Y joystick input for the robot to move in the Y direction.
|
|
* @param angle The desired angle of the robot in radians.
|
|
* @param currentHeadingAngleRadians The current robot heading in radians.
|
|
* @return {@link ChassisSpeeds} which can be sent to th Swerve Drive.
|
|
*/
|
|
public ChassisSpeeds getTargetSpeeds(
|
|
double xInput, double yInput, double angle, double currentHeadingAngleRadians)
|
|
{
|
|
// Convert joystick inputs to m/s by scaling by max linear speed. Also uses a cubic function
|
|
// to allow for precise control and fast movement.
|
|
double x = Math.pow(xInput, 3) * config.maxSpeed;
|
|
double y = Math.pow(yInput, 3) * config.maxSpeed;
|
|
|
|
return getRawTargetSpeeds(x, y, angle, currentHeadingAngleRadians);
|
|
}
|
|
|
|
/**
|
|
* Get the chassis speeds based on controller input of 2 joysticks. One for speeds in which direction. The other for
|
|
* the angle of the robot.
|
|
*
|
|
* @param xInput X joystick input for the robot to move in the X direction.
|
|
* @param yInput Y joystick input for the robot to move in the Y direction.
|
|
* @param headingX X joystick which controls the angle of the robot.
|
|
* @param headingY Y joystick which controls the angle of the robot.
|
|
* @param currentHeadingAngleRadians The current robot heading in radians.
|
|
* @return {@link ChassisSpeeds} which can be sent to th Swerve Drive.
|
|
*/
|
|
public ChassisSpeeds getTargetSpeeds(
|
|
double xInput,
|
|
double yInput,
|
|
double headingX,
|
|
double headingY,
|
|
double currentHeadingAngleRadians)
|
|
{
|
|
// Converts the horizontal and vertical components to the commanded angle, in radians, unless
|
|
// the joystick is near
|
|
// the center (i. e. has been released), in which case the angle is held at the last valid
|
|
// joystick input (hold
|
|
// position when stick released).
|
|
double angle =
|
|
withinHypotDeadband(headingX, headingY) ? lastAngleScalar : Math.atan2(headingX, headingY);
|
|
ChassisSpeeds speeds = getTargetSpeeds(xInput, yInput, angle, currentHeadingAngleRadians);
|
|
|
|
// Used for the position hold feature
|
|
lastAngleScalar = angle;
|
|
|
|
return speeds;
|
|
}
|
|
|
|
/**
|
|
* Get the {@link ChassisSpeeds} based of raw speeds desired in meters/second and heading in radians.
|
|
*
|
|
* @param xSpeed X speed in meters per second.
|
|
* @param ySpeed Y speed in meters per second.
|
|
* @param omega Angular velocity in radians/second.
|
|
* @return {@link ChassisSpeeds} the robot should move to.
|
|
*/
|
|
public ChassisSpeeds getRawTargetSpeeds(double xSpeed, double ySpeed, double omega)
|
|
{
|
|
if (xLimiter != null)
|
|
{
|
|
xSpeed = xLimiter.calculate(xSpeed);
|
|
}
|
|
if (yLimiter != null)
|
|
{
|
|
ySpeed = yLimiter.calculate(ySpeed);
|
|
}
|
|
if (angleLimiter != null)
|
|
{
|
|
omega = angleLimiter.calculate(omega);
|
|
}
|
|
|
|
return new ChassisSpeeds(xSpeed, ySpeed, omega);
|
|
}
|
|
|
|
/**
|
|
* Get the {@link ChassisSpeeds} based of raw speeds desired in meters/second and heading in radians.
|
|
*
|
|
* @param xSpeed X speed in meters per second.
|
|
* @param ySpeed Y speed in meters per second.
|
|
* @param targetHeadingAngleRadians Target heading in radians.
|
|
* @param currentHeadingAngleRadians Current heading in radians.
|
|
* @return {@link ChassisSpeeds} the robot should move to.
|
|
*/
|
|
public ChassisSpeeds getRawTargetSpeeds(double xSpeed, double ySpeed, double targetHeadingAngleRadians,
|
|
double currentHeadingAngleRadians)
|
|
{
|
|
// Calculates an angular rate using a PIDController and the commanded angle. Returns a value between -1 and 1
|
|
// which is then scaled to be between -maxAngularVelocity and +maxAngularVelocity.
|
|
return getRawTargetSpeeds(xSpeed, ySpeed,
|
|
thetaController.calculate(currentHeadingAngleRadians, targetHeadingAngleRadians) *
|
|
config.maxAngularVelocity);
|
|
}
|
|
|
|
}
|