我正在为 ESP32 开发模块开发一些 PID 代码。大多数时候,我执行代码时,
integral
值为 NaN 或 INF。然而,在拔出并重新插入 USB 连接时,偶尔会按预期计算积分值。我已经测试了多种不同类型的开发套件并观察到相同的行为,这让我相信这是一个软件错误。
导致此错误的原因可能是什么?您还建议采取哪些故障排除步骤?
//==============Variables================
// Frequency Counter
const byte interruptPin = 22; // Assign the interrupt pin
volatile uint64_t StartValue = 0; // First interrupt value
volatile uint64_t PeriodCount; // period in counts
float freq; // frequency
hw_timer_t * timer = NULL; // pointer to a variable of type hw_timer_t
// PID
const int OUTPUT_PIN = 23;
double dt = 0.1;
double last_time = 0;
double integral = 0;
double previous = 0;
double output = 75;
double kp, ki, kd;
double setpoint = 35.00; // idle speed of ~35 Hz
//==============Functions================
// Interrupt
void IRAM_ATTR handleInterrupt()
{
uint64_t TempVal = timerRead(timer); // value of timer at interrupt
PeriodCount = TempVal - StartValue; // period count between rising edges
StartValue = TempVal; // puts latest reading as start for next calculation
}
// PID Function
double pid(double error)
{
double proportional = error;
double area = error * dt;
integral += area; // issue found: integral = inf or nan
double derivative = (error - previous) / dt;
previous = error;
double output = (kp * proportional) + (ki * integral) + (kd * derivative);
Serial.print("integral: ");
Serial.println(integral, 6);
}
//=======================================
void setup(){
Serial.begin(115200);
pinMode(interruptPin, INPUT); // sets pin as input
attachInterrupt(interruptPin, handleInterrupt, FALLING); // attaches pin to interrupt on Falling Edge
timer = timerBegin(0, 2, true); // configure timer
// 0 = first timer
// 2 is prescaler so 80 MHZ divided by 2 = 40 MHZ signal
// true - counts up
timerStart(timer); // starts the timer
//=======================================
// PID setup
kp = 0.8;
ki = 0.5;
kd = 0;
last_time = 0;
analogWrite(OUTPUT_PIN, 23);
}
void loop(){
freq = 40000000.00 / ((double) PeriodCount); // calculate frequency
//=======================================
// PID Loop
double now = millis();
dt = (now - last_time) / ((double) 1000);
last_time = now;
delay(1);
double error = freq - setpoint;
output = pid(error); // output is the PWM value
analogWrite(OUTPUT_PIN, output); // set the output pin to the PWM value determined by the output variable
}
我会指出一些容易发现的问题。
PeriodCount
为 0 的情况。这就是您获得 Inf 的方式 :)freq = 40000000.00 / ((double) PeriodCount);