Senior-Design / software / elevate / src / pid_controller.cpp
pid_controller.cpp
Raw
/**
 * @file pid_controller.cpp
 * 
 * @brief elevate module PID controller
 * 
 * @author Jonathan Lee
 * Contact: jonlee27@seas.upenn.edu
 */
#include "pid_controller.h"
#include <Arduino.h>

/**
 * PID Controller constructor
 * 
 * @param kp             proportional coefficient
 * @param ki             integral coefficient
 * @param kd             derivative coefficient
 * @param pid_rate_ms    sample time in ms
 * @param minimum_output minimum output value
 * @param maximum_output maximum output value
 */
PIDController::PIDController(
    float kp,
    float ki,
    float kd,
    unsigned long pid_rate_ms,
    int minimum_output,
    int maximum_output) :
    KP(kp),
    KI(ki),
    KD(kd),
    PID_RATE_MS(pid_rate_ms),
    MINIMUM_OUTPUT(minimum_output),
    MAXIMUM_OUTPUT(maximum_output) {
  mode = OFF;
  previous_time = millis();
  integral_term = 0.0;
  previous_input = 0;
  previous_output = 0;
}

/**
 * Set PID controller to ON or OFF
 * 
 * @param mode mode to set PID controller to
 */
void PIDController::set_mode(Mode mode) {
  if (mode == ON && this->mode == OFF) {
    start();
  }
  this->mode = mode;
}

/**
 * Use PID controller to calculate output
 * 
 * @param setpoint setpoint value
 * @param input    input value
 * 
 * @return output of PID controller
 */
int PIDController::control(long setpoint, long input) {
  if (mode == OFF) return previous_output;

  unsigned long current_time = millis();
  if ((current_time - previous_time) >= PID_RATE_MS) {
    long error = setpoint - input;
    integral_term += KI * error;
    if (integral_term > MAXIMUM_OUTPUT) {
      integral_term = MAXIMUM_OUTPUT;
    } else if (integral_term < MINIMUM_OUTPUT) {
      integral_term < MINIMUM_OUTPUT;
    }
    long input_derivative = input - previous_input;

    int output = (int) (KP * error + integral_term - KD * input_derivative);
    if (output > MAXIMUM_OUTPUT) {
      output = MAXIMUM_OUTPUT;
    } else if (output < MINIMUM_OUTPUT) {
      output = MINIMUM_OUTPUT;
    }

    previous_time = current_time;
    previous_input = input;
    previous_output = output;
    return output;
  }
  
  return previous_output;
}

/**
 * Start PID controller when turned ON
 */
void PIDController::start() {
  integral_term = 0.0;
}