引言
在前面的一篇文章PID控制算法简单说明了PID算法的原理。今天我们一起用C++实现一个简单的PID控制算法吧。
目前实现的是离散位置式PID和增量式PID。
pid_controller.hpp文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #pragma once
namespace control_algorithm { class PID { public: typedef struct { float k; float p; float i; float d; } pid_param;
typedef struct { float i_limit; float d_limit; float out_limit; } pid_limit;
private: typedef struct { float err = 0.0f; float fb = 0.0f; float out = 0.0f; } state;
pid_param pid_param_; pid_limit pid_limit_; state last_; state previous_;
float interget_;
float dt_min_;
float last_time_;
public: PID(PID::pid_param& param, PID::pid_limit& limit, float sample_freq); ~PID(); void SetPidParam(PID::pid_param& param); void SetPidLimit(PID::pid_limit& limit); void SetK(float k); float PositionPIDCalculate(float target, float fb, float dt); float PositionPIDCalculate(float err, float current_time);
float IncrementalPIDCalculate(float target, float fb, float dt); void Reset(); }; }
|
pid_controller.cpp文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| #include "pid_controller.hpp"
#include <algorithm>
using namespace control_algorithm;
PID::PID(PID::pid_param& param, PID::pid_limit& limit, float sample_freq) : pid_param_(param), pid_limit_(limit) { float dt_min = 1.0f / sample_freq; this->dt_min_ = dt_min; this->Reset(); this->SetK(1); }
void PID::Reset() { this->last_ = {0.0f}; this->previous_ = {0.0f}; this->interget_ = 0.0f; }
void PID::SetPidParam(PID::pid_param& param) { this->pid_param_ = param; }
void PID::SetPidLimit(PID::pid_limit& limit) { this->pid_limit_ = limit; } void PID::SetK(float k) { this->pid_param_.k = k; }
float PID::PositionPIDCalculate(float err, float current_time) { float dt = current_time - this->last_time_; if (dt < 0) { return this->last_.out; } else if (dt == 0) { return this->last_.out; } float k_err = this->pid_param_.k * err; float p_out = k_err * this->pid_param_.p;
float d_out = (k_err - this->last_.err * this->pid_param_.k) / std::max(dt, this->dt_min_); d_out *= this->pid_param_.d; d_out = std::clamp(d_out, -this->pid_limit_.d_limit, this->pid_limit_.d_limit);
float interget = this->interget_ + (k_err * dt); interget = std::clamp(interget, -this->pid_limit_.i_limit, this->pid_limit_.i_limit); float i_out = interget * this->pid_param_.i;
this->interget_ = interget;
float output = p_out + d_out + i_out; output = std::clamp(output, -this->pid_limit_.out_limit, this->pid_limit_.out_limit);
this->last_time_ = current_time; this->last_.err = err; this->last_.out = output;
return last_.out; }
float PID::PositionPIDCalculate(float target, float fb, float dt) { float err = target - fb; float k_err = this->pid_param_.k * err; float p_out = k_err * this->pid_param_.p;
float k_fb = this->pid_param_.k * fb;
float d = (k_fb - this->last_.fb * this->pid_param_.k) / std::max(dt, this->dt_min_);
this->last_.err = err; this->last_.fb = fb;
float d_out = -(d * this->pid_param_.d); d_out = std::clamp(d_out, -this->pid_limit_.d_limit, this->pid_limit_.d_limit);
float interget = this->interget_ + (k_err * dt); interget = std::clamp(interget, -this->pid_limit_.i_limit, this->pid_limit_.i_limit); float i_out = interget * this->pid_param_.i;
this->interget_ = interget;
float output = p_out + d_out + i_out; output = std::clamp(output, -this->pid_limit_.out_limit, this->pid_limit_.out_limit);
this->last_.out = output;
return last_.out; }
float PID::IncrementalPIDCalculate(float target, float fb, float dt) { float err = target - fb;
float k_err = this->pid_param_.k * err; float k_last_err = this->pid_param_.k * this->last_.err; float k_previous_err = this->pid_param_.k * this->previous_.err; float delta_p = this->pid_param_.p * (k_err - k_last_err);
float delta_i = this->pid_param_.i * err;
float delta_d = this->pid_param_.d * (k_err - 2 * k_last_err + k_previous_err);
float output = this->last_.out + delta_p + delta_i + delta_d;
output = std::clamp(output, -this->pid_limit_.out_limit, this->pid_limit_.out_limit);
this->previous_.err = this->last_.err; this->last_.err = err; this->previous_.out = this->last_.out; this->last_.out = output;
return output; }
|
main.cpp文件
在main函数中,实例化pid类一个对象,并调用Calculate函数进行计算,即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream>
#include "pid_controller.hpp"
int main() { control_algorithm::PID::pid_param params = {1.0f, 0.1f, 0.01f, 0.05f}; control_algorithm::PID::pid_limit limits = {10.0f, 5.0f, 20.0f};
float sample_freq = 100.0f;
control_algorithm::PID pid_controller(params, limits, sample_freq);
float target = 100.0f; float feedback = 90.0f; float current_time = 0.0f; float dt = 0.01f;
std::cout << "运行PositionPIDCalculate函数:" << std::endl; for (int i = 0; i < 10; ++i) { current_time += dt; float output = pid_controller.PositionPIDCalculate(target, feedback, dt); feedback += output * dt; std::cout << "时间: " << current_time << ",目标: " << target << ",反馈: " << feedback << ",输出: " << output << std::endl; }
std::cout << "\n运行IncrementalPIDCalculate函数:" << std::endl; feedback = 90.0f; for (int i = 0; i < 10; ++i) { current_time += dt; float output = pid_controller.IncrementalPIDCalculate(target, feedback, dt); feedback += output * dt; std::cout << "时间: " << current_time << ",目标: " << target << ",反馈: " << feedback << ",输出: " << output << std::endl; }
return 0; }
|