001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.math.controller;
006
007/**
008 * A helper class that computes feedforward outputs for a simple arm (modeled as a motor acting
009 * against the force of gravity on a beam suspended at an angle).
010 */
011@SuppressWarnings("MemberName")
012public class ArmFeedforward {
013  public final double ks;
014  public final double kcos;
015  public final double kv;
016  public final double ka;
017
018  /**
019   * Creates a new ArmFeedforward with the specified gains. Units of the gain values will dictate
020   * units of the computed feedforward.
021   *
022   * @param ks The static gain.
023   * @param kcos The gravity gain.
024   * @param kv The velocity gain.
025   * @param ka The acceleration gain.
026   */
027  public ArmFeedforward(double ks, double kcos, double kv, double ka) {
028    this.ks = ks;
029    this.kcos = kcos;
030    this.kv = kv;
031    this.ka = ka;
032  }
033
034  /**
035   * Creates a new ArmFeedforward with the specified gains. Acceleration gain is defaulted to zero.
036   * Units of the gain values will dictate units of the computed feedforward.
037   *
038   * @param ks The static gain.
039   * @param kcos The gravity gain.
040   * @param kv The velocity gain.
041   */
042  public ArmFeedforward(double ks, double kcos, double kv) {
043    this(ks, kcos, kv, 0);
044  }
045
046  /**
047   * Calculates the feedforward from the gains and setpoints.
048   *
049   * @param positionRadians The position (angle) setpoint.
050   * @param velocityRadPerSec The velocity setpoint.
051   * @param accelRadPerSecSquared The acceleration setpoint.
052   * @return The computed feedforward.
053   */
054  public double calculate(
055      double positionRadians, double velocityRadPerSec, double accelRadPerSecSquared) {
056    return ks * Math.signum(velocityRadPerSec)
057        + kcos * Math.cos(positionRadians)
058        + kv * velocityRadPerSec
059        + ka * accelRadPerSecSquared;
060  }
061
062  /**
063   * Calculates the feedforward from the gains and velocity setpoint (acceleration is assumed to be
064   * zero).
065   *
066   * @param positionRadians The position (angle) setpoint.
067   * @param velocity The velocity setpoint.
068   * @return The computed feedforward.
069   */
070  public double calculate(double positionRadians, double velocity) {
071    return calculate(positionRadians, velocity, 0);
072  }
073
074  // Rearranging the main equation from the calculate() method yields the
075  // formulas for the methods below:
076
077  /**
078   * Calculates the maximum achievable velocity given a maximum voltage supply, a position, and an
079   * acceleration. Useful for ensuring that velocity and acceleration constraints for a trapezoidal
080   * profile are simultaneously achievable - enter the acceleration constraint, and this will give
081   * you a simultaneously-achievable velocity constraint.
082   *
083   * @param maxVoltage The maximum voltage that can be supplied to the arm.
084   * @param angle The angle of the arm.
085   * @param acceleration The acceleration of the arm.
086   * @return The maximum possible velocity at the given acceleration and angle.
087   */
088  public double maxAchievableVelocity(double maxVoltage, double angle, double acceleration) {
089    // Assume max velocity is positive
090    return (maxVoltage - ks - Math.cos(angle) * kcos - acceleration * ka) / kv;
091  }
092
093  /**
094   * Calculates the minimum achievable velocity given a maximum voltage supply, a position, and an
095   * acceleration. Useful for ensuring that velocity and acceleration constraints for a trapezoidal
096   * profile are simultaneously achievable - enter the acceleration constraint, and this will give
097   * you a simultaneously-achievable velocity constraint.
098   *
099   * @param maxVoltage The maximum voltage that can be supplied to the arm.
100   * @param angle The angle of the arm.
101   * @param acceleration The acceleration of the arm.
102   * @return The minimum possible velocity at the given acceleration and angle.
103   */
104  public double minAchievableVelocity(double maxVoltage, double angle, double acceleration) {
105    // Assume min velocity is negative, ks flips sign
106    return (-maxVoltage + ks - Math.cos(angle) * kcos - acceleration * ka) / kv;
107  }
108
109  /**
110   * Calculates the maximum achievable acceleration given a maximum voltage supply, a position, and
111   * a velocity. Useful for ensuring that velocity and acceleration constraints for a trapezoidal
112   * profile are simultaneously achievable - enter the velocity constraint, and this will give you a
113   * simultaneously-achievable acceleration constraint.
114   *
115   * @param maxVoltage The maximum voltage that can be supplied to the arm.
116   * @param angle The angle of the arm.
117   * @param velocity The velocity of the arm.
118   * @return The maximum possible acceleration at the given velocity.
119   */
120  public double maxAchievableAcceleration(double maxVoltage, double angle, double velocity) {
121    return (maxVoltage - ks * Math.signum(velocity) - Math.cos(angle) * kcos - velocity * kv) / ka;
122  }
123
124  /**
125   * Calculates the minimum achievable acceleration given a maximum voltage supply, a position, and
126   * a velocity. Useful for ensuring that velocity and acceleration constraints for a trapezoidal
127   * profile are simultaneously achievable - enter the velocity constraint, and this will give you a
128   * simultaneously-achievable acceleration constraint.
129   *
130   * @param maxVoltage The maximum voltage that can be supplied to the arm.
131   * @param angle The angle of the arm.
132   * @param velocity The velocity of the arm.
133   * @return The minimum possible acceleration at the given velocity.
134   */
135  public double minAchievableAcceleration(double maxVoltage, double angle, double velocity) {
136    return maxAchievableAcceleration(-maxVoltage, angle, velocity);
137  }
138}