mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
Add feed-forward and slew rate limiting to advanced drive examples (#2301)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
@@ -13,6 +13,7 @@ import edu.wpi.first.wpilibj.PWMVictorSPX;
|
||||
import edu.wpi.first.wpilibj.SpeedController;
|
||||
import edu.wpi.first.wpilibj.SpeedControllerGroup;
|
||||
import edu.wpi.first.wpilibj.controller.PIDController;
|
||||
import edu.wpi.first.wpilibj.controller.SimpleMotorFeedforward;
|
||||
import edu.wpi.first.wpilibj.geometry.Rotation2d;
|
||||
import edu.wpi.first.wpilibj.kinematics.ChassisSpeeds;
|
||||
import edu.wpi.first.wpilibj.kinematics.DifferentialDriveKinematics;
|
||||
@@ -53,6 +54,9 @@ public class Drivetrain {
|
||||
|
||||
private final DifferentialDriveOdometry m_odometry;
|
||||
|
||||
// Gains are for example purposes only - must be determined for your own robot!
|
||||
private final SimpleMotorFeedforward m_feedforward = new SimpleMotorFeedforward(1, 3);
|
||||
|
||||
/**
|
||||
* Constructs a differential drive object.
|
||||
* Sets the encoder distance per pulse and resets the gyro.
|
||||
@@ -88,12 +92,15 @@ public class Drivetrain {
|
||||
* @param speeds The desired wheel speeds.
|
||||
*/
|
||||
public void setSpeeds(DifferentialDriveWheelSpeeds speeds) {
|
||||
double leftOutput = m_leftPIDController.calculate(m_leftEncoder.getRate(),
|
||||
final double leftFeedforward = m_feedforward.calculate(speeds.leftMetersPerSecond);
|
||||
final double rightFeedforward = m_feedforward.calculate(speeds.rightMetersPerSecond);
|
||||
|
||||
final double leftOutput = m_leftPIDController.calculate(m_leftEncoder.getRate(),
|
||||
speeds.leftMetersPerSecond);
|
||||
double rightOutput = m_rightPIDController.calculate(m_rightEncoder.getRate(),
|
||||
final double rightOutput = m_rightPIDController.calculate(m_rightEncoder.getRate(),
|
||||
speeds.rightMetersPerSecond);
|
||||
m_leftGroup.set(leftOutput);
|
||||
m_rightGroup.set(rightOutput);
|
||||
m_leftGroup.setVoltage(leftOutput + leftFeedforward);
|
||||
m_rightGroup.setVoltage(rightOutput + rightFeedforward);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
@@ -8,6 +8,7 @@
|
||||
package edu.wpi.first.wpilibj.examples.differentialdrivebot;
|
||||
|
||||
import edu.wpi.first.wpilibj.GenericHID;
|
||||
import edu.wpi.first.wpilibj.SlewRateLimiter;
|
||||
import edu.wpi.first.wpilibj.TimedRobot;
|
||||
import edu.wpi.first.wpilibj.XboxController;
|
||||
|
||||
@@ -15,6 +16,11 @@ public class Robot extends TimedRobot {
|
||||
private final XboxController m_controller = new XboxController(0);
|
||||
private final Drivetrain m_drive = new Drivetrain();
|
||||
|
||||
// Slew rate limiters to make joystick inputs more gentle; 1/3 sec from 0 to 1.
|
||||
private final SlewRateLimiter m_speedLimiter = new SlewRateLimiter(3);
|
||||
private final SlewRateLimiter m_rotLimiter = new SlewRateLimiter(3);
|
||||
|
||||
|
||||
@Override
|
||||
public void autonomousPeriodic() {
|
||||
teleopPeriodic();
|
||||
@@ -25,13 +31,17 @@ public class Robot extends TimedRobot {
|
||||
public void teleopPeriodic() {
|
||||
// Get the x speed. We are inverting this because Xbox controllers return
|
||||
// negative values when we push forward.
|
||||
final var xSpeed = -m_controller.getY(GenericHID.Hand.kLeft) * Drivetrain.kMaxSpeed;
|
||||
final var xSpeed =
|
||||
-m_speedLimiter.calculate(m_controller.getY(GenericHID.Hand.kLeft))
|
||||
* Drivetrain.kMaxSpeed;
|
||||
|
||||
// Get the rate of angular rotation. We are inverting this because we want a
|
||||
// positive value when we pull to the left (remember, CCW is positive in
|
||||
// mathematics). Xbox controllers return positive values when you pull to
|
||||
// the right by default.
|
||||
final var rot = -m_controller.getX(GenericHID.Hand.kRight) * Drivetrain.kMaxAngularSpeed;
|
||||
final var rot =
|
||||
-m_rotLimiter.calculate(m_controller.getX(GenericHID.Hand.kRight))
|
||||
* Drivetrain.kMaxAngularSpeed;
|
||||
|
||||
m_drive.drive(xSpeed, rot);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
@@ -12,6 +12,7 @@ import edu.wpi.first.wpilibj.Encoder;
|
||||
import edu.wpi.first.wpilibj.PWMVictorSPX;
|
||||
import edu.wpi.first.wpilibj.SpeedController;
|
||||
import edu.wpi.first.wpilibj.controller.PIDController;
|
||||
import edu.wpi.first.wpilibj.controller.SimpleMotorFeedforward;
|
||||
import edu.wpi.first.wpilibj.geometry.Rotation2d;
|
||||
import edu.wpi.first.wpilibj.geometry.Translation2d;
|
||||
import edu.wpi.first.wpilibj.kinematics.ChassisSpeeds;
|
||||
@@ -56,6 +57,9 @@ public class Drivetrain {
|
||||
private final MecanumDriveOdometry m_odometry = new MecanumDriveOdometry(m_kinematics,
|
||||
getAngle());
|
||||
|
||||
// Gains are for example purposes only - must be determined for your own robot!
|
||||
private final SimpleMotorFeedforward m_feedforward = new SimpleMotorFeedforward(1, 3);
|
||||
|
||||
/**
|
||||
* Constructs a MecanumDrive and resets the gyro.
|
||||
*/
|
||||
@@ -93,23 +97,28 @@ public class Drivetrain {
|
||||
* @param speeds The desired wheel speeds.
|
||||
*/
|
||||
public void setSpeeds(MecanumDriveWheelSpeeds speeds) {
|
||||
final var frontLeftOutput = m_frontLeftPIDController.calculate(
|
||||
final double frontLeftFeedforward = m_feedforward.calculate(speeds.frontLeftMetersPerSecond);
|
||||
final double frontRightFeedforward = m_feedforward.calculate(speeds.frontRightMetersPerSecond);
|
||||
final double backLeftFeedforward = m_feedforward.calculate(speeds.rearLeftMetersPerSecond);
|
||||
final double backRightFeedforward = m_feedforward.calculate(speeds.rearRightMetersPerSecond);
|
||||
|
||||
final double frontLeftOutput = m_frontLeftPIDController.calculate(
|
||||
m_frontLeftEncoder.getRate(), speeds.frontLeftMetersPerSecond
|
||||
);
|
||||
final var frontRightOutput = m_frontRightPIDController.calculate(
|
||||
final double frontRightOutput = m_frontRightPIDController.calculate(
|
||||
m_frontRightEncoder.getRate(), speeds.frontRightMetersPerSecond
|
||||
);
|
||||
final var backLeftOutput = m_backLeftPIDController.calculate(
|
||||
final double backLeftOutput = m_backLeftPIDController.calculate(
|
||||
m_backLeftEncoder.getRate(), speeds.rearLeftMetersPerSecond
|
||||
);
|
||||
final var backRightOutput = m_backRightPIDController.calculate(
|
||||
final double backRightOutput = m_backRightPIDController.calculate(
|
||||
m_backRightEncoder.getRate(), speeds.rearRightMetersPerSecond
|
||||
);
|
||||
|
||||
m_frontLeftMotor.set(frontLeftOutput);
|
||||
m_frontRightMotor.set(frontRightOutput);
|
||||
m_backLeftMotor.set(backLeftOutput);
|
||||
m_backRightMotor.set(backRightOutput);
|
||||
m_frontLeftMotor.setVoltage(frontLeftOutput + frontLeftFeedforward);
|
||||
m_frontRightMotor.setVoltage(frontRightOutput + frontRightFeedforward);
|
||||
m_backLeftMotor.setVoltage(backLeftOutput + backLeftFeedforward);
|
||||
m_backRightMotor.setVoltage(backRightOutput + backRightFeedforward);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
@@ -8,6 +8,7 @@
|
||||
package edu.wpi.first.wpilibj.examples.mecanumbot;
|
||||
|
||||
import edu.wpi.first.wpilibj.GenericHID;
|
||||
import edu.wpi.first.wpilibj.SlewRateLimiter;
|
||||
import edu.wpi.first.wpilibj.TimedRobot;
|
||||
import edu.wpi.first.wpilibj.XboxController;
|
||||
|
||||
@@ -15,6 +16,11 @@ public class Robot extends TimedRobot {
|
||||
private final XboxController m_controller = new XboxController(0);
|
||||
private final Drivetrain m_mecanum = new Drivetrain();
|
||||
|
||||
// Slew rate limiters to make joystick inputs more gentle; 1/3 sec from 0 to 1.
|
||||
private final SlewRateLimiter m_xspeedLimiter = new SlewRateLimiter(3);
|
||||
private final SlewRateLimiter m_yspeedLimiter = new SlewRateLimiter(3);
|
||||
private final SlewRateLimiter m_rotLimiter = new SlewRateLimiter(3);
|
||||
|
||||
@Override
|
||||
public void autonomousPeriodic() {
|
||||
driveWithJoystick(false);
|
||||
@@ -29,18 +35,24 @@ public class Robot extends TimedRobot {
|
||||
private void driveWithJoystick(boolean fieldRelative) {
|
||||
// Get the x speed. We are inverting this because Xbox controllers return
|
||||
// negative values when we push forward.
|
||||
final var xSpeed = -m_controller.getY(GenericHID.Hand.kLeft) * Drivetrain.kMaxSpeed;
|
||||
final var xSpeed =
|
||||
-m_xspeedLimiter.calculate(m_controller.getY(GenericHID.Hand.kLeft))
|
||||
* Drivetrain.kMaxSpeed;
|
||||
|
||||
// Get the y speed or sideways/strafe speed. We are inverting this because
|
||||
// we want a positive value when we pull to the left. Xbox controllers
|
||||
// return positive values when you pull to the right by default.
|
||||
final var ySpeed = -m_controller.getX(GenericHID.Hand.kLeft) * Drivetrain.kMaxSpeed;
|
||||
final var ySpeed =
|
||||
-m_yspeedLimiter.calculate(m_controller.getX(GenericHID.Hand.kLeft))
|
||||
* Drivetrain.kMaxSpeed;
|
||||
|
||||
// Get the rate of angular rotation. We are inverting this because we want a
|
||||
// positive value when we pull to the left (remember, CCW is positive in
|
||||
// mathematics). Xbox controllers return positive values when you pull to
|
||||
// the right by default.
|
||||
final var rot = -m_controller.getX(GenericHID.Hand.kRight) * Drivetrain.kMaxAngularSpeed;
|
||||
final var rot =
|
||||
-m_rotLimiter.calculate(m_controller.getX(GenericHID.Hand.kRight))
|
||||
* Drivetrain.kMaxAngularSpeed;
|
||||
|
||||
m_mecanum.drive(xSpeed, ySpeed, rot, fieldRelative);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
@@ -8,6 +8,7 @@
|
||||
package edu.wpi.first.wpilibj.examples.swervebot;
|
||||
|
||||
import edu.wpi.first.wpilibj.GenericHID;
|
||||
import edu.wpi.first.wpilibj.SlewRateLimiter;
|
||||
import edu.wpi.first.wpilibj.TimedRobot;
|
||||
import edu.wpi.first.wpilibj.XboxController;
|
||||
|
||||
@@ -15,6 +16,11 @@ public class Robot extends TimedRobot {
|
||||
private final XboxController m_controller = new XboxController(0);
|
||||
private final Drivetrain m_swerve = new Drivetrain();
|
||||
|
||||
// Slew rate limiters to make joystick inputs more gentle; 1/3 sec from 0 to 1.
|
||||
private final SlewRateLimiter m_xspeedLimiter = new SlewRateLimiter(3);
|
||||
private final SlewRateLimiter m_yspeedLimiter = new SlewRateLimiter(3);
|
||||
private final SlewRateLimiter m_rotLimiter = new SlewRateLimiter(3);
|
||||
|
||||
@Override
|
||||
public void autonomousPeriodic() {
|
||||
driveWithJoystick(false);
|
||||
@@ -29,18 +35,24 @@ public class Robot extends TimedRobot {
|
||||
private void driveWithJoystick(boolean fieldRelative) {
|
||||
// Get the x speed. We are inverting this because Xbox controllers return
|
||||
// negative values when we push forward.
|
||||
final var xSpeed = -m_controller.getY(GenericHID.Hand.kLeft) * Drivetrain.kMaxSpeed;
|
||||
final var xSpeed =
|
||||
-m_xspeedLimiter.calculate(m_controller.getY(GenericHID.Hand.kLeft))
|
||||
* edu.wpi.first.wpilibj.examples.mecanumbot.Drivetrain.kMaxSpeed;
|
||||
|
||||
// Get the y speed or sideways/strafe speed. We are inverting this because
|
||||
// we want a positive value when we pull to the left. Xbox controllers
|
||||
// return positive values when you pull to the right by default.
|
||||
final var ySpeed = -m_controller.getX(GenericHID.Hand.kLeft) * Drivetrain.kMaxSpeed;
|
||||
final var ySpeed =
|
||||
-m_yspeedLimiter.calculate(m_controller.getX(GenericHID.Hand.kLeft))
|
||||
* edu.wpi.first.wpilibj.examples.mecanumbot.Drivetrain.kMaxSpeed;
|
||||
|
||||
// Get the rate of angular rotation. We are inverting this because we want a
|
||||
// positive value when we pull to the left (remember, CCW is positive in
|
||||
// mathematics). Xbox controllers return positive values when you pull to
|
||||
// the right by default.
|
||||
final var rot = -m_controller.getX(GenericHID.Hand.kRight) * Drivetrain.kMaxAngularSpeed;
|
||||
final var rot =
|
||||
-m_rotLimiter.calculate(m_controller.getX(GenericHID.Hand.kRight))
|
||||
* edu.wpi.first.wpilibj.examples.mecanumbot.Drivetrain.kMaxAngularSpeed;
|
||||
|
||||
m_swerve.drive(xSpeed, ySpeed, rot, fieldRelative);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
@@ -12,6 +12,7 @@ import edu.wpi.first.wpilibj.PWMVictorSPX;
|
||||
import edu.wpi.first.wpilibj.SpeedController;
|
||||
import edu.wpi.first.wpilibj.controller.PIDController;
|
||||
import edu.wpi.first.wpilibj.controller.ProfiledPIDController;
|
||||
import edu.wpi.first.wpilibj.controller.SimpleMotorFeedforward;
|
||||
import edu.wpi.first.wpilibj.geometry.Rotation2d;
|
||||
import edu.wpi.first.wpilibj.kinematics.SwerveModuleState;
|
||||
import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
|
||||
@@ -36,6 +37,10 @@ public class SwerveModule {
|
||||
= new ProfiledPIDController(1, 0, 0,
|
||||
new TrapezoidProfile.Constraints(kModuleMaxAngularVelocity, kModuleMaxAngularAcceleration));
|
||||
|
||||
// Gains are for example purposes only - must be determined for your own robot!
|
||||
private final SimpleMotorFeedforward m_driveFeedforward = new SimpleMotorFeedforward(1, 3);
|
||||
private final SimpleMotorFeedforward m_turnFeedforward = new SimpleMotorFeedforward(1, 0.5);
|
||||
|
||||
/**
|
||||
* Constructs a SwerveModule.
|
||||
*
|
||||
@@ -77,16 +82,20 @@ public class SwerveModule {
|
||||
*/
|
||||
public void setDesiredState(SwerveModuleState state) {
|
||||
// Calculate the drive output from the drive PID controller.
|
||||
final var driveOutput = m_drivePIDController.calculate(
|
||||
final double driveOutput = m_drivePIDController.calculate(
|
||||
m_driveEncoder.getRate(), state.speedMetersPerSecond);
|
||||
|
||||
final double driveFeedforward = m_driveFeedforward.calculate(state.speedMetersPerSecond);
|
||||
|
||||
// Calculate the turning motor output from the turning PID controller.
|
||||
final var turnOutput = m_turningPIDController.calculate(
|
||||
final double turnOutput = m_turningPIDController.calculate(
|
||||
m_turningEncoder.get(), state.angle.getRadians()
|
||||
);
|
||||
|
||||
// Calculate the turning motor output from the turning PID controller.
|
||||
m_driveMotor.set(driveOutput);
|
||||
m_turningMotor.set(turnOutput);
|
||||
final double turnFeedforward =
|
||||
m_turnFeedforward.calculate(m_turningPIDController.getSetpoint().velocity);
|
||||
|
||||
m_driveMotor.setVoltage(driveOutput + driveFeedforward);
|
||||
m_turningMotor.setVoltage(turnOutput + turnFeedforward);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user