ПИД-регулятор для управления скоростью двигателя
Я пытался применить ПИ-регулятор к двигателю с помощью Arduino. Я в некоторой степени справился с задачей, но проблема в том, что она слишком сильно колеблется. Также я не мог понять, что делать, если ШИМ-сигнал считается отрицательным
int counter = 0;
double end_time=0;
double ini_time=0;
double rpm=0;
double my_time=0;
double temp = 0;
int pid_speed=0;
float kp=2.25;
float ki=.01;
float kd=0.005;
int prev_error=0;
double pwm_sig=0;
int integrator = 0;
int motor_sig_pin= 5;
int error=0;
int absolute = 0;
float desired_rpm=1000; //мое желаемое значение числа оборотов в минуту
double zero_time=0;
double i_time=0;
double f_time=0;
int rpm_tacho=0;
int previous_error=0;
int derivative=0;
void setup() {
pinMode(2,INPUT);
digitalWrite(2,HIGH);
pinMode(motor_sig_pin,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
digitalWrite(9,HIGH);
digitalWrite(10,LOW );
attachInterrupt (0,Count,RISING);
ini_time = micros();
i_time=micros();
Serial.begin(115200);
}
void Count(){ //вычисление времени для одного раунда с помощью кодировщика
counter++;
if (counter>=100){
end_time=micros()-ini_time;
ini_time=micros();
counter=0;
}
}
void loop() {
rpm = ((1000000*60)/(end_time));
rpm = abs(rpm);
rpm_tacho = ((1000000*60)/(zero_time));
if (rpm <10 || rpm>5000){
rpm=0;
}
error=desired_rpm-rpm;
integrator += error;
pid_speed = kp*error; + ki*integrator;
pid_speed=(int)pid_speed;
Serial.print(pid_speed);
Serial.print(" ");
if (pid_speed> 0){
if (pid_speed>255)
analogWrite(motor_sig_pin,255);
else
analogWrite(motor_sig_pin,pid_speed);
}
if(pid_speed<0){
if(pid_speed<-255)
{
analogWrite(motor_sig_pin,0);
}
else
{
pid_speed=abs(pid_speed);
analogWrite(motor_sig_pin,255-pid_speed);
}
}
Serial.print (" ");
Serial.println(rpm);
}
@Adnan, 👍0
Обсуждение2 ответа
Вместо того, чтобы думать о выходе ПИД-регулятора как о pid_speed, думайте о нем как о мощности двигателя, и то, что делает ПИ-регулятор, — это переводит ошибки в оборотах в настройку мощности двигателя.
Вероятно, вы получаете колебания из-за интегрального сбоя. Если ваш цикл быстрый по сравнению с вашей системой, ошибка каждого цикла добавляется к интегратору быстрее/быстрее, чем система может отрегулировать. Например, если цикл занимает 1 мс, ошибка в 100 об/мин может переполнить «интегратор int» за 32768 всего за 0,327 секунды и за порог, при котором интегратор может привязать выход 25500 (= 255/Ki) всего за 0,255 секунды. интегратор быстрее системы, он легко может вызвать перерегулирование. Вы можете рассмотреть возможность замедления цикла до 10 мс, 100 мс или 1000 с, чтобы соответствовать физическому процессу и сделать член kI разумным преобразованием rpmErrorсекунд/100 интегратора, rpmErrorсекунд/10 или rpmError*. секунд на выходную мощность.
Чтобы лучше обрабатывать числовые значения и ограничения, такие как переполнение интеграторов и отрицательные выходные значения, вероятно, лучше всего использовать библиотеку PID Arduino из http://playground.arduino.cc/Code/PIDLibrary как в комментарии Эдгара Боне.
Я не знаю, существует ли этот вопрос еще или вам удалось его решить. Тем не менее, я работал (до сих пор работаю) над самобалансирующимся роботом, где я также столкнулся с такой проблемой и Я пришел на этот форум. Я решил эту проблему, установив выходы ПИД-регулятора (при условии, что вы используете библиотеку ПИД-регуляторов Arduino) от 0 до 255 вместо -255 до 255. Теперь для моего проекта мне нужно было изменить направление вращения двигателя в зависимости от угла наклона двигателя. робот. Итак, каждый раз, когда мне нужно изменить направление вращения двигателя, я делаю следующее
- Сначала я сбрасываю Iterm (или обнуляю его).
- Измените направление вращения.
- Снова начните вычисление PID.
Раньше я тоже пытался добиться этого от -255 до 255, но это было очень рывками, и я не был уверен, что это правильный способ сделать это. С моим нынешним подходом мне удалось решить мою проблему.
- Управление скоростью вентилятора с помощью библиотеки Arduino PID
- Попытка контролировать скорость двигателя постоянного тока с помощью ПИД
- Как устранить шум от вентилятора 12 В с ШИМ-управлением на низкой скорости
- Генерация частоты ШИМ выше 125 кГц с помощью Arduino Uno
- Увеличить разрядность PWM
- Как вывести истинное аналоговое напряжение на выходной контакт
- Как управлять 6 шаговыми двигателями с помощью Arduino?
- Синусоидальный инвертор
Всего несколько комментариев: 1)
end_time
используется как в обычном контексте, так и в контексте прерывания, поэтому его следует квалифицировать как "летучий". 2) В цикле, посколькуend_time
занимает больше одного байта, вам следует скопировать его в локальную переменную, блокируя прерывания. 3) Вы не используетеkd
. 4) Перед+ ki*integrator
стоит;
, что означает, что вычисление интегрального члена не является операцией., @Edgar Bonet@EdgarBonet, что вы подразумеваете под блокировкой прерывания., @Adnan
noInterrupts(); двойной end_time_copy = end_time; прерывания();
, затем используйте копию вместо оригинала. В противном случаеCount()
может обновитьend_time
, пока вы его читаете., @Edgar Bonet5)
ini_time
иend_time
должны бытьunsigned long
илиuint32_t
, иначе тахометр вернет мусор, когдаmicros()
обнулится. 6) Тогда нет смысла вabs(rpm)
, посколькуrpm
не может быть отрицательным. 7)rpm_tacho
не используется и вычисляется путем деления на ноль. 8) Перед публикацией кода необходимо правильно сделать отступ., @Edgar Bonet9) Вам также следует удалить все переменные, которые вы никогда не используете. 10) Нет смысла приводить int к int. 11) Ваш набор if...else выглядит слишком сложным, почему бы просто не
constrain(pid_speed, 0, 255)
? 12) Не следует выполнятьSerial.print()
на каждой итерации цикла, поскольку его слишком много для чтения, и это замедляетloop()
. 13) Но тогда вам следует контролировать частоту обновления или свой PID., @Edgar BonetРасчеты pid также выдают отрицательные значения, что мне для этого делать?? @ЭдгарБонет, @Adnan
[
constrain()
](http://www.arduino.cc/en/Reference/Constrain). Или, еще лучше, используйте готовую [библиотеку PID](http://playground.arduino.cc/Code/PIDLibrary)., @Edgar Bonetfloat kp=2,25;
; Я не думаю, что пропорциональная часть должна быть больше «1,0», но здесь я могу ошибаться., @Gerben@Gerben: kp может быть больше 1. Оно должно быть любым, необходимым для преобразования измеренной входной ошибки в выходные данные процесса. Если бы входными данными были радианы в секунду, а не об/мин, kp должно быть в 2*pi*60=376 раз больше, чем kP было бы для датчика, измеряющего обороты в минуту., @Dave X