У меня есть PID, управляющий двигателем постоянного тока. Я пытаюсь очень точно контролировать скорость двигателя. Мой контроллер позволяет мне изменять направление вращения двигателя и задавать ему скорость. Поэтому у меня есть PID, у которого есть плюс и минус максимум и минимум. Для того, чтобы ускорить устройство и замедлить устройство достаточно быстро. Выход PID предназначен для pwm и, следовательно, является абсолютным значением PID, просто изменяя вывод направления, когда PID < 0. Я использую противоположное направление двигателя только в качестве тормозной системы. Таким образом, двигатель всегда должен двигаться в одном направлении, но должен быстрее замедляться, применяя обратный крутящий момент.
Я пишу прошивку C в MCUXpresso. Графики получаются при отправке данных через UART на Arduino, чтобы легко отображать данные.
Моя проблема заключается в том, что иногда, когда переменная процесса достигает 0 или близко к нему, ПИД-регулятор инвертируется и должен стать отрицательным, и, таким образом, двигатель вращается на полной скорости в противоположном направлении. На двух рисунках ниже показаны определенные случаи, когда это произошло. Красная линия – это уставка, а синяя линия – переменная процесса.
Код, управляющий устройством и PID, приведен ниже.
Мне трудно понять, почему PID убегает вот так. Любая помощь была бы потрясающей. Спасибо!
Основной контроль
int dir = FORWARD; //Controls direction of motor
motorPID.setpoint = vehicleSpeed;
motorPID.input = SM_GetRPM();
motorPID.input = motorPID.input * speedConversion;
UART_SendPID((uint8_t)motorPID.input, (uint8_t)motorPID.setpoint);
PID_Compute(&motorPID);
if(motorPID.output < 0){
dir = BACKWARD;
}
if(motorPID.setpoint == 0){
motorPID.output = 0;
}
if(motorPID.input > 60){
MC_SetMotorSpeed(0, dir);
int test = 0;
}
MC_SetMotorSpeed(abs(motorPID.output),dir);
PID-код
//Find all error variables
self->lastError = self->error;
double input = self->input; //Only so input can't change during compute
self->error = self->setpoint - input;
self->integral += self->error;
double derivative = self->error - self->lastError;
//Anti-integral Windup
if(self->integral > self->Outmax)
self->integral = self->Outmax;
else if(self->integral < self->Outmin)
self->integral = self->Outmin;
//Calculate PID
self->output = (self->Kp*self->error) + (self->Ki * self->integral) + (self->Kd * derivative);
//Set limits
if(self->output > self->Outmax)
self->output = self->Outmax;
else if(self->output < self->Outmin)
self->output = self->Outmin;
РЕДАКТИРОВАТЬ: оказалось, что это была комбинированная ошибка описанной проблемы и проблемы с оборудованием.
Попробуйте изменить строку, которая читает
self->integral += self->error;
к
self->integral += self-> Ki * self->error;
и сопоставьте это, изменив строку, которая читает
self->output = (self->Kp*self->error) + (self->Ki * self->integral) + (self->Kd * derivative);
к
self->output = (self->Kp*self->error) + self->integral + (self->Kd * derivative);
Это позволит правильно масштабировать интегральный член для вашего ограничивающего шага интегратора.
судя по вашим графикам, я не думаю, что вы производите выборку с достаточно высокой частотой для достижения стабильности... Хотя это может быть ограничением Arduino, так как я не знаком с MCUExpresso.
В идеале у вас должно быть математическое описание вашей системы, чтобы у вас была передаточная функция, после чего вы могли бы просто считать пропускную способность из передаточной функции. Эта полоса пропускания также является частотой Найквиста, которая является минимальной «приемлемой» (используя это слово в широком смысле) частотой выборки сигнала. Обычно вы хотите сэмплировать примерно в 30-40 раз больше частоты Найквиста. Если это невозможно, я предлагаю заменить датчики.
Я столкнулся с подобными проблемами в прошлом семестре в университете в своем проекте, надеюсь, это поможет!
Транзистор
Тим Вескотт
Тим Вескотт
Дрю Фаулер