Skip to content

Instantly share code, notes, and snippets.

@saxbophone
Last active January 2, 2016 15:39
Show Gist options
  • Save saxbophone/ba13b1347bb21906fc0d to your computer and use it in GitHub Desktop.
Save saxbophone/ba13b1347bb21906fc0d to your computer and use it in GitHub Desktop.
My own attempt at implementing the PID algorithm in some (hopefully) clean, understandable C
/*
* PID Controller Implementation in C
*
* Created by Joshua Saxby (aka @saxbophone) on 1 Jan, 2016
*
* My own attempt at implementing the PID algorithm in some (hopefully) clean, understandable C.
* No warranty, no patenting (LOL!), free use, yadda yadda etc, hope you find this useful and don't be evil!
*/
#include <stdio.h>
#include "pid.c"
int main(int argc, char const *argv[]) {
/*
* DEMO MAIN FUNCTION JUST TO TEST THAT THIS WORKS!
*/
static short true = 1;
// initialise a calibration for our PID controller
PID_Calibration calibration;
// dummy values
calibration.kp = 1.0;
calibration.ki = 1.0;
calibration.kd = 1.0;
// initialise the starting state of the controller
PID_State current_state;
// we need to populate all fields apart from output, as this one gets populated by the algorithm
// set all variables to neutral values
current_state.actual = 0.0;
current_state.target = 0.0;
current_state.time_delta = 1.0; // AFIAK this will make timing have no effect...
current_state.previous_error = 0.0; // no errors yet
current_state.integral = 0.0; // no errors yet
// get target value from user
printf("Enter Target Value:\t");
scanf("%lf", &current_state.target);
// do several iterations of the algorithm
while (true) {
// get actual value from user
printf("Enter Actual Value:\t");
scanf("%lf", &current_state.actual);
// run the algorithm
current_state = pid_iterate(calibration, current_state);
// output results for info
printf(
"Actual:\t%lf\tTarget:\t%lf\tOutput:\t%lf\n",
current_state.actual, current_state.target, current_state.output
);
}
return 0;
}
/*
* PID Controller Implementation in C
*
* Created by Joshua Saxby (aka @saxbophone) on 1 Jan, 2016
*
* My own attempt at implementing the PID algorithm in some (hopefully) clean, understandable C.
* No warranty, no patenting (LOL!), free use, yadda yadda etc, hope you find this useful and don't be evil!
*/
typedef struct {
/*
* struct PID_Calibration
*
* Struct storing calibrated PID constants for a PID Controller
* These are used for tuning the algorithm and the values they take are
* dependent upon the application - (in other words, YMMV...)
*/
double kp; // Proportional gain
double ki; // Integral gain
double kd; // Derivative gain
} PID_Calibration;
typedef struct {
/*
* struct PID_State
*
* Struct storing the current state of a PID Controller.
* This is used as the input value to the PID algorithm function, which also
* returns a PID_State struct reflecting the adjustments suggested by the algorithm.
*
* NOTE: The output field in this struct is set by the PID algorithm function, and
* is ignored in the actual calculations.
*/
double actual; // The actual reading as measured
double target; // The desired reading
double time_delta; // Time since last sample/calculation - should be set when updating state
// The previously calculated error between actual and target (zero initially)
double previous_error;
double integral; // Sum of integral error over time
double output; // the modified output value calculated by the algorithm, to compensate for error
} PID_State;
PID_State pid_iterate(PID_Calibration calibration, PID_State state) {
/*
* PID Controller Algorithm implementation
*
* Given a PID calibration for the P, I and D values and a PID_State for the current
* state of the PID controller, calculate the new state for the PID Controller and set
* the output state to compensate for any error as defined by the algorithm
*/
// calculate difference between desired and actual values (the error)
double error = state.target - state.actual;
// calculate and update integral
state.integral += (error * state.time_delta);
// calculate derivative
double derivative = (error - state.previous_error) / state.time_delta;
// calculate output value according to algorithm
state.output = (
(calibration.kp * error) + (calibration.ki * state.integral) + (calibration.kd * derivative)
);
// update state.previous_error to the error value calculated on this iteration
state.previous_error = error;
// return the state struct reflecting the calculations
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment