001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-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;
009
010import java.util.TimerTask;
011import java.util.concurrent.locks.ReentrantLock;
012
013import edu.wpi.first.wpilibj.filters.LinearDigitalFilter;
014import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
015import edu.wpi.first.wpilibj.util.BoundaryException;
016
017import static java.util.Objects.requireNonNull;
018
019/**
020 * Class implements a PID Control Loop.
021 *
022 * <p>Creates a separate thread which reads the given PIDSource and takes care of the integral
023 * calculations, as well as writing the given PIDOutput.
024 *
025 * <p>This feedback controller runs in discrete time, so time deltas are not used in the integral
026 * and derivative calculations. Therefore, the sample rate affects the controller's behavior for a
027 * given set of PID constants.
028 */
029public class PIDController extends SendableBase implements PIDInterface, Sendable, Controller {
030  public static final double kDefaultPeriod = .05;
031  private static int instances = 0;
032  @SuppressWarnings("MemberName")
033  private double m_P; // factor for "proportional" control
034  @SuppressWarnings("MemberName")
035  private double m_I; // factor for "integral" control
036  @SuppressWarnings("MemberName")
037  private double m_D; // factor for "derivative" control
038  @SuppressWarnings("MemberName")
039  private double m_F; // factor for feedforward term
040  private double m_maximumOutput = 1.0; // |maximum output|
041  private double m_minimumOutput = -1.0; // |minimum output|
042  private double m_maximumInput = 0.0; // maximum input - limit setpoint to this
043  private double m_minimumInput = 0.0; // minimum input - limit setpoint to this
044  private double m_inputRange = 0.0; // input range - difference between maximum and minimum
045  // do the endpoints wrap around? eg. Absolute encoder
046  private boolean m_continuous = false;
047  private boolean m_enabled = false; // is the pid controller enabled
048  // the prior error (used to compute velocity)
049  private double m_prevError = 0.0;
050  // the sum of the errors for use in the integral calc
051  private double m_totalError = 0.0;
052  // the tolerance object used to check if on target
053  private Tolerance m_tolerance;
054  private double m_setpoint = 0.0;
055  private double m_prevSetpoint = 0.0;
056  @SuppressWarnings("PMD.UnusedPrivateField")
057  private double m_error = 0.0;
058  private double m_result = 0.0;
059  private double m_period = kDefaultPeriod;
060
061  PIDSource m_origSource;
062  LinearDigitalFilter m_filter;
063
064  ReentrantLock m_thisMutex = new ReentrantLock();
065
066  // Ensures when disable() is called, pidWrite() won't run if calculate()
067  // is already running at that time.
068  ReentrantLock m_pidWriteMutex = new ReentrantLock();
069
070  protected PIDSource m_pidInput;
071  protected PIDOutput m_pidOutput;
072  java.util.Timer m_controlLoop;
073  Timer m_setpointTimer;
074
075  /**
076   * Tolerance is the type of tolerance used to specify if the PID controller is on target.
077   *
078   * <p>The various implementations of this class such as PercentageTolerance and AbsoluteTolerance
079   * specify types of tolerance specifications to use.
080   */
081  public interface Tolerance {
082    boolean onTarget();
083  }
084
085  /**
086   * Used internally for when Tolerance hasn't been set.
087   */
088  public class NullTolerance implements Tolerance {
089    @Override
090    public boolean onTarget() {
091      throw new RuntimeException("No tolerance value set when calling onTarget().");
092    }
093  }
094
095  public class PercentageTolerance implements Tolerance {
096    private final double m_percentage;
097
098    PercentageTolerance(double value) {
099      m_percentage = value;
100    }
101
102    @Override
103    public boolean onTarget() {
104      return Math.abs(getError()) < m_percentage / 100 * m_inputRange;
105    }
106  }
107
108  public class AbsoluteTolerance implements Tolerance {
109    private final double m_value;
110
111    AbsoluteTolerance(double value) {
112      m_value = value;
113    }
114
115    @Override
116    public boolean onTarget() {
117      return Math.abs(getError()) < m_value;
118    }
119  }
120
121  private class PIDTask extends TimerTask {
122    private PIDController m_controller;
123
124    PIDTask(PIDController controller) {
125      requireNonNull(controller, "Given PIDController was null");
126
127      m_controller = controller;
128    }
129
130    @Override
131    public void run() {
132      m_controller.calculate();
133    }
134  }
135
136  /**
137   * Allocate a PID object with the given constants for P, I, D, and F.
138   *
139   * @param Kp     the proportional coefficient
140   * @param Ki     the integral coefficient
141   * @param Kd     the derivative coefficient
142   * @param Kf     the feed forward term
143   * @param source The PIDSource object that is used to get values
144   * @param output The PIDOutput object that is set to the output percentage
145   * @param period the loop time for doing calculations. This particularly effects calculations of
146   *               the integral and differential terms. The default is 50ms.
147   */
148  @SuppressWarnings("ParameterName")
149  public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
150                       PIDOutput output, double period) {
151    super(false);
152    requireNonNull(source, "Null PIDSource was given");
153    requireNonNull(output, "Null PIDOutput was given");
154
155    m_controlLoop = new java.util.Timer();
156    m_setpointTimer = new Timer();
157    m_setpointTimer.start();
158
159    m_P = Kp;
160    m_I = Ki;
161    m_D = Kd;
162    m_F = Kf;
163
164    // Save original source
165    m_origSource = source;
166
167    // Create LinearDigitalFilter with original source as its source argument
168    m_filter = LinearDigitalFilter.movingAverage(m_origSource, 1);
169    m_pidInput = m_filter;
170
171    m_pidOutput = output;
172    m_period = period;
173
174    m_controlLoop.schedule(new PIDTask(this), 0L, (long) (m_period * 1000));
175
176    instances++;
177    HLUsageReporting.reportPIDController(instances);
178    m_tolerance = new NullTolerance();
179    setName("PIDController", instances);
180  }
181
182  /**
183   * Allocate a PID object with the given constants for P, I, D and period.
184   *
185   * @param Kp     the proportional coefficient
186   * @param Ki     the integral coefficient
187   * @param Kd     the derivative coefficient
188   * @param source the PIDSource object that is used to get values
189   * @param output the PIDOutput object that is set to the output percentage
190   * @param period the loop time for doing calculations. This particularly effects calculations of
191   *               the integral and differential terms. The default is 50ms.
192   */
193  @SuppressWarnings("ParameterName")
194  public PIDController(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output,
195                       double period) {
196    this(Kp, Ki, Kd, 0.0, source, output, period);
197  }
198
199  /**
200   * Allocate a PID object with the given constants for P, I, D, using a 50ms period.
201   *
202   * @param Kp     the proportional coefficient
203   * @param Ki     the integral coefficient
204   * @param Kd     the derivative coefficient
205   * @param source The PIDSource object that is used to get values
206   * @param output The PIDOutput object that is set to the output percentage
207   */
208  @SuppressWarnings("ParameterName")
209  public PIDController(double Kp, double Ki, double Kd, PIDSource source, PIDOutput output) {
210    this(Kp, Ki, Kd, source, output, kDefaultPeriod);
211  }
212
213  /**
214   * Allocate a PID object with the given constants for P, I, D, using a 50ms period.
215   *
216   * @param Kp     the proportional coefficient
217   * @param Ki     the integral coefficient
218   * @param Kd     the derivative coefficient
219   * @param Kf     the feed forward term
220   * @param source The PIDSource object that is used to get values
221   * @param output The PIDOutput object that is set to the output percentage
222   */
223  @SuppressWarnings("ParameterName")
224  public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
225                       PIDOutput output) {
226    this(Kp, Ki, Kd, Kf, source, output, kDefaultPeriod);
227  }
228
229  /**
230   * Free the PID object.
231   */
232  @Override
233  public void free() {
234    super.free();
235    m_controlLoop.cancel();
236    m_thisMutex.lock();
237    try {
238      m_pidOutput = null;
239      m_pidInput = null;
240      m_controlLoop = null;
241    } finally {
242      m_thisMutex.unlock();
243    }
244  }
245
246  /**
247   * Read the input, calculate the output accordingly, and write to the output. This should only be
248   * called by the PIDTask and is created during initialization.
249   */
250  @SuppressWarnings("LocalVariableName")
251  protected void calculate() {
252    if (m_origSource == null || m_pidOutput == null) {
253      return;
254    }
255
256    boolean enabled;
257
258    m_thisMutex.lock();
259    try {
260      enabled = m_enabled;
261    } finally {
262      m_thisMutex.unlock();
263    }
264
265    if (enabled) {
266      double input;
267
268      // Storage for function inputs
269      PIDSourceType pidSourceType;
270      double P;
271      double I;
272      double D;
273      double feedForward = calculateFeedForward();
274      double minimumOutput;
275      double maximumOutput;
276
277      // Storage for function input-outputs
278      double prevError;
279      double error;
280      double totalError;
281
282      m_thisMutex.lock();
283      try {
284        input = m_pidInput.pidGet();
285
286        pidSourceType = m_pidInput.getPIDSourceType();
287        P = m_P;
288        I = m_I;
289        D = m_D;
290        minimumOutput = m_minimumOutput;
291        maximumOutput = m_maximumOutput;
292
293        prevError = m_prevError;
294        error = getContinuousError(m_setpoint - input);
295        totalError = m_totalError;
296      } finally {
297        m_thisMutex.unlock();
298      }
299
300      // Storage for function outputs
301      double result;
302
303      if (pidSourceType.equals(PIDSourceType.kRate)) {
304        if (P != 0) {
305          totalError = clamp(totalError + error, minimumOutput / P,
306              maximumOutput / P);
307        }
308
309        result = P * totalError + D * error + feedForward;
310      } else {
311        if (I != 0) {
312          totalError = clamp(totalError + error, minimumOutput / I,
313              maximumOutput / I);
314        }
315
316        result = P * error + I * totalError + D * (error - prevError)
317            + feedForward;
318      }
319
320      result = clamp(result, minimumOutput, maximumOutput);
321
322      // Ensures m_enabled check and pidWrite() call occur atomically
323      m_pidWriteMutex.lock();
324      try {
325        m_thisMutex.lock();
326        try {
327          if (m_enabled) {
328            // Don't block other PIDController operations on pidWrite()
329            m_thisMutex.unlock();
330
331            m_pidOutput.pidWrite(result);
332          }
333        } finally {
334          if (m_thisMutex.isHeldByCurrentThread()) {
335            m_thisMutex.unlock();
336          }
337        }
338      } finally {
339        m_pidWriteMutex.unlock();
340      }
341
342      m_thisMutex.lock();
343      try {
344        m_prevError = error;
345        m_error = error;
346        m_totalError = totalError;
347        m_result = result;
348      } finally {
349        m_thisMutex.unlock();
350      }
351    }
352  }
353
354  /**
355   * Calculate the feed forward term.
356   *
357   * <p>Both of the provided feed forward calculations are velocity feed forwards. If a different
358   * feed forward calculation is desired, the user can override this function and provide his or
359   * her own. This function  does no synchronization because the PIDController class only calls it
360   * in synchronized code, so be careful if calling it oneself.
361   *
362   * <p>If a velocity PID controller is being used, the F term should be set to 1 over the maximum
363   * setpoint for the output. If a position PID controller is being used, the F term should be set
364   * to 1 over the maximum speed for the output measured in setpoint units per this controller's
365   * update period (see the default period in this class's constructor).
366   */
367  protected double calculateFeedForward() {
368    if (m_pidInput.getPIDSourceType().equals(PIDSourceType.kRate)) {
369      return m_F * getSetpoint();
370    } else {
371      double temp = m_F * getDeltaSetpoint();
372      m_prevSetpoint = m_setpoint;
373      m_setpointTimer.reset();
374      return temp;
375    }
376  }
377
378  /**
379   * Set the PID Controller gain parameters. Set the proportional, integral, and differential
380   * coefficients.
381   *
382   * @param p Proportional coefficient
383   * @param i Integral coefficient
384   * @param d Differential coefficient
385   */
386  @SuppressWarnings("ParameterName")
387  public void setPID(double p, double i, double d) {
388    m_thisMutex.lock();
389    try {
390      m_P = p;
391      m_I = i;
392      m_D = d;
393    } finally {
394      m_thisMutex.unlock();
395    }
396  }
397
398  /**
399   * Set the PID Controller gain parameters. Set the proportional, integral, and differential
400   * coefficients.
401   *
402   * @param p Proportional coefficient
403   * @param i Integral coefficient
404   * @param d Differential coefficient
405   * @param f Feed forward coefficient
406   */
407  @SuppressWarnings("ParameterName")
408  public void setPID(double p, double i, double d, double f) {
409    m_thisMutex.lock();
410    try {
411      m_P = p;
412      m_I = i;
413      m_D = d;
414      m_F = f;
415    } finally {
416      m_thisMutex.unlock();
417    }
418  }
419
420  /**
421   * Set the Proportional coefficient of the PID controller gain.
422   *
423   * @param p Proportional coefficient
424   */
425  @SuppressWarnings("ParameterName")
426  public void setP(double p) {
427    m_thisMutex.lock();
428    try {
429      m_P = p;
430    } finally {
431      m_thisMutex.unlock();
432    }
433  }
434
435  /**
436   * Set the Integral coefficient of the PID controller gain.
437   *
438   * @param i Integral coefficient
439   */
440  @SuppressWarnings("ParameterName")
441  public void setI(double i) {
442    m_thisMutex.lock();
443    try {
444      m_I = i;
445    } finally {
446      m_thisMutex.unlock();
447    }
448  }
449
450  /**
451   * Set the Differential coefficient of the PID controller gain.
452   *
453   * @param d differential coefficient
454   */
455  @SuppressWarnings("ParameterName")
456  public void setD(double d) {
457    m_thisMutex.lock();
458    try {
459      m_D = d;
460    } finally {
461      m_thisMutex.unlock();
462    }
463  }
464
465  /**
466   * Set the Feed forward coefficient of the PID controller gain.
467   *
468   * @param f feed forward coefficient
469   */
470  @SuppressWarnings("ParameterName")
471  public void setF(double f) {
472    m_thisMutex.lock();
473    try {
474      m_F = f;
475    } finally {
476      m_thisMutex.unlock();
477    }
478  }
479
480  /**
481   * Get the Proportional coefficient.
482   *
483   * @return proportional coefficient
484   */
485  public double getP() {
486    m_thisMutex.lock();
487    try {
488      return m_P;
489    } finally {
490      m_thisMutex.unlock();
491    }
492  }
493
494  /**
495   * Get the Integral coefficient.
496   *
497   * @return integral coefficient
498   */
499  public double getI() {
500    m_thisMutex.lock();
501    try {
502      return m_I;
503    } finally {
504      m_thisMutex.unlock();
505    }
506  }
507
508  /**
509   * Get the Differential coefficient.
510   *
511   * @return differential coefficient
512   */
513  public double getD() {
514    m_thisMutex.lock();
515    try {
516      return m_D;
517    } finally {
518      m_thisMutex.unlock();
519    }
520  }
521
522  /**
523   * Get the Feed forward coefficient.
524   *
525   * @return feed forward coefficient
526   */
527  public double getF() {
528    m_thisMutex.lock();
529    try {
530      return m_F;
531    } finally {
532      m_thisMutex.unlock();
533    }
534  }
535
536  /**
537   * Return the current PID result This is always centered on zero and constrained the the max and
538   * min outs.
539   *
540   * @return the latest calculated output
541   */
542  public double get() {
543    m_thisMutex.lock();
544    try {
545      return m_result;
546    } finally {
547      m_thisMutex.unlock();
548    }
549  }
550
551  /**
552   * Set the PID controller to consider the input to be continuous, Rather then using the max and
553   * min input range as constraints, it considers them to be the same point and automatically
554   * calculates the shortest route to the setpoint.
555   *
556   * @param continuous Set to true turns on continuous, false turns off continuous
557   */
558  public void setContinuous(boolean continuous) {
559    if (continuous && m_inputRange <= 0) {
560      throw new RuntimeException("No input range set when calling setContinuous().");
561    }
562    m_thisMutex.lock();
563    try {
564      m_continuous = continuous;
565    } finally {
566      m_thisMutex.unlock();
567    }
568  }
569
570  /**
571   * Set the PID controller to consider the input to be continuous, Rather then using the max and
572   * min input range as constraints, it considers them to be the same point and automatically
573   * calculates the shortest route to the setpoint.
574   */
575  public void setContinuous() {
576    setContinuous(true);
577  }
578
579  /**
580   * Sets the maximum and minimum values expected from the input and setpoint.
581   *
582   * @param minimumInput the minimum value expected from the input
583   * @param maximumInput the maximum value expected from the input
584   */
585  public void setInputRange(double minimumInput, double maximumInput) {
586    m_thisMutex.lock();
587    try {
588      if (minimumInput > maximumInput) {
589        throw new BoundaryException("Lower bound is greater than upper bound");
590      }
591      m_minimumInput = minimumInput;
592      m_maximumInput = maximumInput;
593      m_inputRange = maximumInput - minimumInput;
594    } finally {
595      m_thisMutex.unlock();
596    }
597
598    setSetpoint(m_setpoint);
599  }
600
601  /**
602   * Sets the minimum and maximum values to write.
603   *
604   * @param minimumOutput the minimum percentage to write to the output
605   * @param maximumOutput the maximum percentage to write to the output
606   */
607  public void setOutputRange(double minimumOutput, double maximumOutput) {
608    m_thisMutex.lock();
609    try {
610      if (minimumOutput > maximumOutput) {
611        throw new BoundaryException("Lower bound is greater than upper bound");
612      }
613      m_minimumOutput = minimumOutput;
614      m_maximumOutput = maximumOutput;
615    } finally {
616      m_thisMutex.unlock();
617    }
618  }
619
620  /**
621   * Set the setpoint for the PIDController.
622   *
623   * @param setpoint the desired setpoint
624   */
625  public void setSetpoint(double setpoint) {
626    m_thisMutex.lock();
627    try {
628      if (m_maximumInput > m_minimumInput) {
629        if (setpoint > m_maximumInput) {
630          m_setpoint = m_maximumInput;
631        } else if (setpoint < m_minimumInput) {
632          m_setpoint = m_minimumInput;
633        } else {
634          m_setpoint = setpoint;
635        }
636      } else {
637        m_setpoint = setpoint;
638      }
639    } finally {
640      m_thisMutex.unlock();
641    }
642  }
643
644  /**
645   * Returns the current setpoint of the PIDController.
646   *
647   * @return the current setpoint
648   */
649  public double getSetpoint() {
650    m_thisMutex.lock();
651    try {
652      return m_setpoint;
653    } finally {
654      m_thisMutex.unlock();
655    }
656  }
657
658  /**
659   * Returns the change in setpoint over time of the PIDController.
660   *
661   * @return the change in setpoint over time
662   */
663  public double getDeltaSetpoint() {
664    m_thisMutex.lock();
665    try {
666      return (m_setpoint - m_prevSetpoint) / m_setpointTimer.get();
667    } finally {
668      m_thisMutex.unlock();
669    }
670  }
671
672  /**
673   * Returns the current difference of the input from the setpoint.
674   *
675   * @return the current error
676   */
677  public double getError() {
678    m_thisMutex.lock();
679    try {
680      return getContinuousError(getSetpoint() - m_pidInput.pidGet());
681    } finally {
682      m_thisMutex.unlock();
683    }
684  }
685
686  /**
687   * Returns the current difference of the error over the past few iterations. You can specify the
688   * number of iterations to average with setToleranceBuffer() (defaults to 1). getAvgError() is
689   * used for the onTarget() function.
690   *
691   * @deprecated Use getError(), which is now already filtered.
692   * @return     the current average of the error
693   */
694  @Deprecated
695  public double getAvgError() {
696    m_thisMutex.lock();
697    try {
698      return getError();
699    } finally {
700      m_thisMutex.unlock();
701    }
702  }
703
704  /**
705   * Sets what type of input the PID controller will use.
706   *
707   * @param pidSource the type of input
708   */
709  void setPIDSourceType(PIDSourceType pidSource) {
710    m_pidInput.setPIDSourceType(pidSource);
711  }
712
713  /**
714   * Returns the type of input the PID controller is using.
715   *
716   * @return the PID controller input type
717   */
718  PIDSourceType getPIDSourceType() {
719    return m_pidInput.getPIDSourceType();
720  }
721
722  /**
723   * Set the PID tolerance using a Tolerance object. Tolerance can be specified as a percentage of
724   * the range or as an absolute value. The Tolerance object encapsulates those options in an
725   * object. Use it by creating the type of tolerance that you want to use: setTolerance(new
726   * PIDController.AbsoluteTolerance(0.1))
727   *
728   * @deprecated      Use setPercentTolerance() instead.
729   * @param tolerance A tolerance object of the right type, e.g. PercentTolerance or
730   *                  AbsoluteTolerance
731   */
732  @Deprecated
733  public void setTolerance(Tolerance tolerance) {
734    m_tolerance = tolerance;
735  }
736
737  /**
738   * Set the absolute error which is considered tolerable for use with OnTarget.
739   *
740   * @param absvalue absolute error which is tolerable in the units of the input object
741   */
742  public void setAbsoluteTolerance(double absvalue) {
743    m_thisMutex.lock();
744    try {
745      m_tolerance = new AbsoluteTolerance(absvalue);
746    } finally {
747      m_thisMutex.unlock();
748    }
749  }
750
751  /**
752   * Set the percentage error which is considered tolerable for use with OnTarget. (Input of 15.0 =
753   * 15 percent)
754   *
755   * @param percentage percent error which is tolerable
756   */
757  public void setPercentTolerance(double percentage) {
758    m_thisMutex.lock();
759    try {
760      m_tolerance = new PercentageTolerance(percentage);
761    } finally {
762      m_thisMutex.unlock();
763    }
764  }
765
766  /**
767   * Set the number of previous error samples to average for tolerancing. When determining whether a
768   * mechanism is on target, the user may want to use a rolling average of previous measurements
769   * instead of a precise position or velocity. This is useful for noisy sensors which return a few
770   * erroneous measurements when the mechanism is on target. However, the mechanism will not
771   * register as on target for at least the specified bufLength cycles.
772   *
773   * @deprecated      Use a LinearDigitalFilter as the input.
774   * @param bufLength Number of previous cycles to average.
775   */
776  @Deprecated
777  public void setToleranceBuffer(int bufLength) {
778    m_thisMutex.lock();
779    try {
780      m_filter = LinearDigitalFilter.movingAverage(m_origSource, bufLength);
781      m_pidInput = m_filter;
782    } finally {
783      m_thisMutex.unlock();
784    }
785  }
786
787  /**
788   * Return true if the error is within the percentage of the total input range, determined by
789   * setTolerance. This assumes that the maximum and minimum input were set using setInput.
790   *
791   * @return true if the error is less than the tolerance
792   */
793  public boolean onTarget() {
794    m_thisMutex.lock();
795    try {
796      return m_tolerance.onTarget();
797    } finally {
798      m_thisMutex.unlock();
799    }
800  }
801
802  /**
803   * Begin running the PIDController.
804   */
805  @Override
806  public void enable() {
807    m_thisMutex.lock();
808    try {
809      m_enabled = true;
810    } finally {
811      m_thisMutex.unlock();
812    }
813  }
814
815  /**
816   * Stop running the PIDController, this sets the output to zero before stopping.
817   */
818  @Override
819  public void disable() {
820    // Ensures m_enabled check and pidWrite() call occur atomically
821    m_pidWriteMutex.lock();
822    try {
823      m_thisMutex.lock();
824      try {
825        m_enabled = false;
826      } finally {
827        m_thisMutex.unlock();
828      }
829
830      m_pidOutput.pidWrite(0);
831    } finally {
832      m_pidWriteMutex.unlock();
833    }
834  }
835
836  /**
837   * Set the enabled state of the PIDController.
838   */
839  public void setEnabled(boolean enable) {
840    if (enable) {
841      enable();
842    } else {
843      disable();
844    }
845  }
846
847  /**
848   * Return true if PIDController is enabled.
849   */
850  @Override
851  public boolean isEnabled() {
852    m_thisMutex.lock();
853    try {
854      return m_enabled;
855    } finally {
856      m_thisMutex.unlock();
857    }
858  }
859
860  /**
861   * Reset the previous error,, the integral term, and disable the controller.
862   */
863  @Override
864  public void reset() {
865    disable();
866
867    m_thisMutex.lock();
868    try {
869      m_prevError = 0;
870      m_totalError = 0;
871      m_result = 0;
872    } finally {
873      m_thisMutex.unlock();
874    }
875  }
876
877  @Override
878  public void initSendable(SendableBuilder builder) {
879    builder.setSmartDashboardType("PIDController");
880    builder.setSafeState(this::reset);
881    builder.addDoubleProperty("p", this::getP, this::setP);
882    builder.addDoubleProperty("i", this::getI, this::setI);
883    builder.addDoubleProperty("d", this::getD, this::setD);
884    builder.addDoubleProperty("f", this::getF, this::setF);
885    builder.addDoubleProperty("setpoint", this::getSetpoint, this::setSetpoint);
886    builder.addBooleanProperty("enabled", this::isEnabled, this::setEnabled);
887  }
888
889  /**
890   * Wraps error around for continuous inputs. The original error is returned if continuous mode is
891   * disabled. This is an unsynchronized function.
892   *
893   * @param error The current error of the PID controller.
894   * @return Error for continuous inputs.
895   */
896  protected double getContinuousError(double error) {
897    if (m_continuous && m_inputRange > 0) {
898      error %= m_inputRange;
899      if (Math.abs(error) > m_inputRange / 2) {
900        if (error > 0) {
901          return error - m_inputRange;
902        } else {
903          return error + m_inputRange;
904        }
905      }
906    }
907
908    return error;
909  }
910
911  private static double clamp(double value, double low, double high) {
912    return Math.max(low, Math.min(value, high));
913  }
914}