001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj.drive;
009
010import edu.wpi.first.wpilibj.MotorSafety;
011import edu.wpi.first.wpilibj.MotorSafetyHelper;
012import edu.wpi.first.wpilibj.SendableBase;
013
014/**
015 * Common base class for drive platforms.
016 */
017public abstract class RobotDriveBase extends SendableBase implements MotorSafety {
018  public static final double kDefaultDeadband = 0.02;
019  public static final double kDefaultMaxOutput = 1.0;
020
021  protected double m_deadband = kDefaultDeadband;
022  protected double m_maxOutput = kDefaultMaxOutput;
023  protected MotorSafetyHelper m_safetyHelper = new MotorSafetyHelper(this);
024
025  /**
026   * The location of a motor on the robot for the purpose of driving.
027   */
028  public enum MotorType {
029    kFrontLeft(0), kFrontRight(1), kRearLeft(2), kRearRight(3), kLeft(0),
030    kRight(1), kBack(2);
031
032    @SuppressWarnings("MemberName")
033    public final int value;
034
035    MotorType(int value) {
036      this.value = value;
037    }
038  }
039
040  public RobotDriveBase() {
041    m_safetyHelper.setSafetyEnabled(true);
042    setName("RobotDriveBase");
043  }
044
045  /**
046   * Change the default value for deadband scaling. The default value is
047   * {@value #kDefaultDeadband}. Values smaller then the deadband are set to 0, while values
048   * larger then the deadband are scaled from 0.0 to 1.0. See {@link #applyDeadband}.
049   *
050   * @param deadband The deadband to set.
051   */
052  public void setDeadband(double deadband) {
053    m_deadband = deadband;
054  }
055
056  /**
057   * Configure the scaling factor for using drive methods with motor controllers in a mode other
058   * than PercentVbus or to limit the maximum output.
059   *
060   * <p>The default value is {@value #kDefaultMaxOutput}.
061   *
062   * @param maxOutput Multiplied with the output percentage computed by the drive functions.
063   */
064  public void setMaxOutput(double maxOutput) {
065    m_maxOutput = maxOutput;
066  }
067
068  @Override
069  public void setExpiration(double timeout) {
070    m_safetyHelper.setExpiration(timeout);
071  }
072
073  @Override
074  public double getExpiration() {
075    return m_safetyHelper.getExpiration();
076  }
077
078  @Override
079  public boolean isAlive() {
080    return m_safetyHelper.isAlive();
081  }
082
083  @Override
084  public abstract void stopMotor();
085
086  @Override
087  public boolean isSafetyEnabled() {
088    return m_safetyHelper.isSafetyEnabled();
089  }
090
091  @Override
092  public void setSafetyEnabled(boolean enabled) {
093    m_safetyHelper.setSafetyEnabled(enabled);
094  }
095
096  @Override
097  public abstract String getDescription();
098
099  /**
100   * Limit motor values to the -1.0 to +1.0 range.
101   */
102  protected double limit(double value) {
103    if (value > 1.0) {
104      return 1.0;
105    }
106    if (value < -1.0) {
107      return -1.0;
108    }
109    return value;
110  }
111
112  /**
113   * Returns 0.0 if the given value is within the specified range around zero. The remaining range
114   * between the deadband and 1.0 is scaled from 0.0 to 1.0.
115   *
116   * @param value    value to clip
117   * @param deadband range around zero
118   */
119  protected double applyDeadband(double value, double deadband) {
120    if (Math.abs(value) > deadband) {
121      if (value > 0.0) {
122        return (value - deadband) / (1.0 - deadband);
123      } else {
124        return (value + deadband) / (1.0 - deadband);
125      }
126    } else {
127      return 0.0;
128    }
129  }
130
131  /**
132   * Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
133   */
134  protected void normalize(double[] wheelSpeeds) {
135    double maxMagnitude = Math.abs(wheelSpeeds[0]);
136    for (int i = 1; i < wheelSpeeds.length; i++) {
137      double temp = Math.abs(wheelSpeeds[i]);
138      if (maxMagnitude < temp) {
139        maxMagnitude = temp;
140      }
141    }
142    if (maxMagnitude > 1.0) {
143      for (int i = 0; i < wheelSpeeds.length; i++) {
144        wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
145      }
146    }
147  }
148}