Регулятор оборотов коллекторного двигателя

flying
Offline
Зарегистрирован: 12.11.2011

 Здравствуйте.

Делаю регулятор оборотов двигателя, програмку написал все отлично регулируется.

Но есть не решенный вопрос, как мне поддерживать напряжение подаваемое на двигатель когда он под нагрузкой? Тоесть измеряю напряжение на двигателе (это не сложно, сделал), знаю приблизительное напряжение которое задаю ШИМом. А вот все это связать пока не могу.

Буду очень благодарен.

step962
Offline
Зарегистрирован: 23.05.2011

flying пишет:

, как мне поддерживать напряжение подаваемое на двигатель когда он под нагрузкой? 

А вы думаете, это имеет смысл?

Ведь при разном моменте на валу напряжение, необходимое для поддержания требуемой скорости вращения, будет разным. Иными словами, если вы будете стабилизировать напряжение на обмотках двигателя, с ростом момента на валу он будет вращаться все медленнее и медленнее.

Полученную схему сложно - если не невозможно - будет назвать регулятором оборотов.

flying
Offline
Зарегистрирован: 12.11.2011

 Я хочу попробовать, а что будет то будет.

Двигатель у меня мощный, 3 киловата, но на низких оборотах легко остановить, что не желательно.

Mastino
Offline
Зарегистрирован: 03.12.2011

а если encoder поставить?

step962
Offline
Зарегистрирован: 23.05.2011

 Сотрется.

Датчик Холла - более оптимальный вариант.

2 flying:

Ну, если вы умеете считывать напряжение на обмотках, то знать, какое напряжение вы генерируете с помощью ШИМ, в общем-то и не обязательно. Запрограммируйте простейшую систему слежения (за напряжением на двигателе). Для этого, например каждые полсекунды:

- считывайте напряжение на обмотках

- сравнивайте его с заданной величиной

- если напряжение меньше заданного - увеличьте значение для ШИМ на единицу

- если напряжение больше заданного - уменьшите значение для ШИМ на единицу

 - подавайте на двигатель напряжение, сгенерированное с новым значением ШИМ

Двигатель у вас довольно инерционный и в принципе возможно возникновение автоколебаний. когда напряжение на двигателе будет с некоторой амплитудой и периодом в несколько циклов измерения изменяться около заданного значения. Чтобы предотвратить возникновение автоколебаний, можно ввести "мертвую зону" - Uзад+/-дельта. В этой зоне ШИМ изменяться не будет. Какое значение дельта взять? Ну попробуйте 2% от Uзад. Не поможет - возьмите 5%.

carduino.ru
Offline
Зарегистрирован: 06.12.2011

Оптический Энеодер сотрется? Есть опыт? 

На большинстве роботах пылесосах используют именно оптический энкодер  

flying
Offline
Зарегистрирован: 12.11.2011

Спасибо за советы, энкодеры и дитчики ставить не хоу по причине что нужно все это быстро заменить на станке. В данный момент станок работает и простой не желательный. Так что буду мудрить за изменением напряжения.

step962 пишет:

Ну, если вы умеете считывать напряжение на обмотках, то знать, какое напряжение вы генерируете с помощью ШИМ, в общем-то и не обязательно. Запрограммируйте простейшую систему слежения (за напряжением на двигателе). Для этого, например каждые полсекунды:

А не поможете примером программы, а то с arduino начал работать недавно и еще не все знаю как правильно сделать.

step962
Offline
Зарегистрирован: 23.05.2011

carduino.ru пишет:

Оптический Энеодер сотрется? Есть опыт? 

кроме оптических есть еще и механические:

flying
Offline
Зарегистрирован: 12.11.2011

 Механический не подойдет, не расчитан он на такие обороты. На крайний случай датчик холла могу поставить, но и с кодом у меня пока проблематично.

carduino.ru
Offline
Зарегистрирован: 06.12.2011

step962 пишет:

carduino.ru пишет:

Оптический Энеодер сотрется? Есть опыт? 

кроме оптических есть еще и механические:

Ну я думаю что никому в голову не придет такая мысль, использовать механический энкодер в электроприводе
 

step962
Offline
Зарегистрирован: 23.05.2011

 Ну, тут иногда гораздо более ценные идеи обсуждаются.

Mastino
Offline
Зарегистрирован: 03.12.2011

step962 пишет:

 Ну, тут иногда гораздо более ценные идеи обсуждаются.

Золотые слова, Юрий Венедиктович!:)

flying
Offline
Зарегистрирован: 12.11.2011

Что никто не поможет?

step962
Offline
Зарегистрирован: 23.05.2011

flying пишет:

Что никто не поможет?

С чем именно? Снимать напряжение вы уже умеете, управлять ШИМ-ом, надеюсь, тоже. Что остается? Изменять параметры ШИМ в зависимости от измеренного напряжения? Но ведь это, как говорится, как два пальца об асфальт:

if(Umeasured<Uspecified-delta) {
  if(PWMvalue<PWMmax) {
    PWMvalue++;
  }
  else {
// PWM уже на верхнем пределе - дальнейшее увеличение невозможно
  }
}
else if(Umeasured>Uspecified+delta) {
  if(PWMvalue>PWMmin) {
    PWMvalue--;
  }
  else {
// PWM уже на нижнем пределе - дальнейшее снижение невозможно
  }
}
else {
// Umeasured в пределах допуска - ничего не делаем
}

 Umeasured - измеренное значение напряжения
Uspecified - к этому напряжению мы стремимся
delta определяет диапазон напряжений, где можно успокоиться
PWMvalue - параметр для генерации ШИМ-сигнала
PWMmin - например, 0 - ниже спускаться или не имеет смысла, или опасно
PWMmax - например, 255 - выше подниматься или не имеет смысла, или опасно

 

Это если совсем простенько. Можно ввести, например, еще одну дкльту - delta2, которая будет определять диапазон напряжений, за пределами которого изменение PWM будет производиться шагом, скажем, 10. Это позволит в ускоренном темпе восстанавливать напряжение на двигателе в случае его значительного отклонения от оптимального.

maksim
Offline
Зарегистрирован: 12.02.2012

По-моему, если вы хотите сделать регулятор оборотов, то измерять скорость вращения двигателя по напряжению все-така не правильно. Самый простой датчик оборотов - это ИК-диод в паре с фототранзистором:

и пятно черной краски на валу двигателя. А дальше читайте про ПИД-регулирование, т.к. код, который написал  step962 выше будет из-за отсутствия задежек (времени интегрирования) при изменении PWMvalue работать как позиционный регулятор (ПД-регулятор) т.е. это тоже самое, что управлять двигателем через реле. И основная проблема не в написании кода, а в правильном подборе параметров регулирования...

 

flying
Offline
Зарегистрирован: 12.11.2011

 Получил я датчик холла, нашел программку для измерения оборотов, но у меня при одних и тех же оборотах постоянно разное значение. Про ПИД почитал вро де все ясно пока, но с оборотами не понятно.

 
 #define PotPin 0 // potentiometer 
  #define pwmPinA 9 // pwm out
  int PotAnalog;
  
volatile byte rpmcount;
 unsigned int rpm;

 unsigned long timeold;

 void setup()
 {
   Serial.begin(9600);
   attachInterrupt(0, rpm_fun, RISING);

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 }

 void loop()
 {
   PotAnalog=((analogRead(PotPin))/4);
   analogWrite(pwmPinA, PotAnalog);
   
   if (rpmcount >= 20) { 
     //Update RPM every 20 counts, increase this for better RPM resolution,
     //decrease for faster update
     rpm = 30*1000/(millis() - timeold)*rpmcount;
     timeold = millis();
     rpmcount = 0;
     Serial.println(rpm,DEC);
   }
 }

 void rpm_fun()
 {
   rpmcount++;
   //Each rotation, this interrupt function is run twice
 }

 

maksim
Offline
Зарегистрирован: 12.02.2012

А вы к какому выводу датчик подключали? и как подключали? если можно, то схему нарисуйте

flying
Offline
Зарегистрирован: 12.11.2011

 Подключал к цифровому 2, подтягивал +5В через резистор 10к. Думаю схема не нужна.

maksim
Offline
Зарегистрирован: 12.02.2012

А какой датчик хола используете? Какое на него напряжение подаете?

flying
Offline
Зарегистрирован: 12.11.2011

 Датчик использую от электронного зажигания (типа такого http://www.hobbyking.com/hobbyking/store/__17620__FTL_Engines_Hall_Senso...), подаю 5В

maksim
Offline
Зарегистрирован: 12.02.2012

Вы понимаете, что бы у вас этот датчик заработал нужен еще магнит (правильно расположенный по отношению к датчику) и зубчатое колесо (или хотябы один зуб на валу, который будет проходить между датчиком и магнитом) или магнит правильно расположенный по отношению к датчику на валу.

Попробуите убрать подтягивающий резистор и вот этот скейтч:

void setup() {
  Serial.begin(9600);
  digitalWrite(2, 1); // "подтяжка" к +5В без внешнего резистора
}

void loop() {
  Serial.println(pulseIn(2, HIGH, 3000000), DEC);
}

Чем выше обороты двигателя, тем меньше значение (в микросекундах) выводимое в сириал монитор, если датчик работает нормально, то значение будет колебаться в разумных пределах, если показывает 0, то это означает, что либо датчик подключен или работает не верно, либо зуб проходит мимо датчика реже, чем один раз в три секунды. И еще попробуйте без "подтяжки" удалите или закомментируйте 3-ю строку:
 

void setup() {
  Serial.begin(9600);
  //digitalWrite(2, 1); // "подтяжка" к +5В без внешнего резистора
}

 

flying
Offline
Зарегистрирован: 12.11.2011

 Про то как работает датчик знаю. Дело в том что при постоянных оборотах значение меняется (например) от 600 до 2000

Ваш код выводит только 0 

maksim
Offline
Зарегистрирован: 12.02.2012

Если мой код дает 0 и обороты вала больше чем 1 оборот в 3 секунды, значит датчик или не правильно установлен либо не верно подключен т.е. при работе датчика (если он вообще работает) возникают колебония напряжения в диапазон которых не попадает (или частично попадает) пороговый уровень переключения между 0 и 1. Если не ошибаюсь, то при нормальных условиях при напряжении питания МК 5В этот уровень примерно 1,9В.

maksim
Offline
Зарегистрирован: 12.02.2012

Попробуйте мультиметром померить напряжения на сигнальном проводе датчика, когда магнит рядом с датчиком и когда не рядом. В измеренный вами диапазон напряжений должно с запасом (хотябы +/- 1В) попасть пороговое напряжение 1,9В.

flying
Offline
Зарегистрирован: 12.11.2011

 На второй ноге напряжение от 0 рядом и 4,5 когда не рядом). Датчик был взят с работающего зажигания так что он полностью рабочий.

maksim
Offline
Зарегистрирован: 12.02.2012

А если так:

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(pulseIn(2, LOW), DEC);
}

Какие примерно обороты у вала и сколько раз срабатывает датчик за 1 оборот?

flying
Offline
Зарегистрирован: 12.11.2011

 Так показывает, значения очень большие (4-6 значные)

maksim
Offline
Зарегистрирован: 12.02.2012

А в больших пределах колеблется?

 

flying
Offline
Зарегистрирован: 12.11.2011

Сечас точнее проверил то

14785
14808
14720
14685
14649
14564
14584
14493
14446
14443
14487
14460
14706
14785
14685
14634
14644
14622
14788
14607
14757
14660
14589
14580
14585
14416
14476
14353
14349
14324
14365
 

не так то и плохо.

maksim
Offline
Зарегистрирован: 12.02.2012

Я бы даже сказал, что очень хорошо 

flying
Offline
Зарегистрирован: 12.11.2011

 А как это все перевести в обороты?

maksim
Offline
Зарегистрирован: 12.02.2012

С подтяжкой такие же значения? Если да то вот так: 

void setup() {
  Serial.begin(9600);
  digitalWrite(2, 1);
}

void loop() {
  Serial.println((1000000/pulseIn(2, LOW))*60, DEC); // об/мин
}

на число 4294967236 пока можно не обращать внимания это результат деления на 0. Если с подтяжкой другие значения то уберите ее.
 

maksim
Offline
Зарегистрирован: 12.02.2012

Это если за 1 оборот датчик срабатывает 1 раз. Вы мне так и не написали сколько раз у вас срабатывает датчик за 1 оборот. Так сколько раз???

flying
Offline
Зарегистрирован: 12.11.2011

 Сейчас примерно 400 оборотов в мин. с 100000 примерно похоже на правду.  

maksim
Offline
Зарегистрирован: 12.02.2012

maksim пишет:

Это если за 1 оборот датчик срабатывает 1 раз. Вы мне так и не написали сколько раз у вас срабатывает датчик за 1 оборот. Так сколько раз???

Еще раз спрашиваю, сколько у вас магнитов или зубов на валу???? Это очень важно для расчета

flying
Offline
Зарегистрирован: 12.11.2011

 1 магнит. За 1 один оборот 1 импульс. 

maksim
Offline
Зарегистрирован: 12.02.2012

flying пишет:

 Сейчас примерно 400 оборотов в мин. с 100000 примерно похоже на правду.  

я так понял вы вот это значение изменили: Serial.println((1000000/pulseIn(2, LOW))*60, DEC); // об/мин?

flying
Offline
Зарегистрирован: 12.11.2011

 Да, это значение.

maksim
Offline
Зарегистрирован: 12.02.2012

Вот смотрите. 

Функция pulseIn() возвращет значение в микросекундах от первого срабатывания датчика до последующего, т.е. в вашем случае это за сколько микросикунд вал делает один оборот. В секунде 1 000 000 (милион) микросекунд, значит, что бы вычислить сколько оборотов делат вал в секунду нужно 1000000 микросекунд поделить на количество микросекунд за 1 оборот(1000000/pulseIn() ).

В одной минуте 60 секунд, следовательно количество оборотов в минуту равно 60 секунд умножить на количество оборотов в секунду. 

х об./мин. = 60*(1000000/мкс за 1 об.)

maksim
Offline
Зарегистрирован: 12.02.2012

Так что теоретически вы должны получать правильное значение

flying
Offline
Зарегистрирован: 12.11.2011

 При 1000000 показует около 4000. Мне главное поддерживать крутящий момент на низких оборотах.

maksim
Offline
Зарегистрирован: 12.02.2012

Ну так это же правильное значение, причем тут низкие обороты? При изменении расчета количества оборотов реальные же обороты не меняются.

maksim
Offline
Зарегистрирован: 12.02.2012

А вот если вы хотите округлять, то можно вот так: (1000000/(pulseIn(2, LOW)/10)*10)*60

maksim
Offline
Зарегистрирован: 12.02.2012

 Ну или так (100000/(pulseIn(2, LOW)/10))*60, хотите еще большего округления так (10000/(pulseIn(2, LOW)/100))*60
 

maksim
Offline
Зарегистрирован: 12.02.2012

И всетаки попробуйте еще раз

void setup() {
Serial.begin(9600);
}

void loop() {
Serial.println(pulseIn(2, HIGH), DEC);
}

Потому что если учитывать время пока датчик "замкнут" правильнее было бы так:

Serial.println((1000000/(pulseIn(2, HIGH)+pulseIn(2, LOW)))*60, DEC);

 

maksim
Offline
Зарегистрирован: 12.02.2012

Ну кажатся всё, все мои предыдущие коды на дрова и в топку, вот так точно должно правильные обороты показывать:

long micros1 = 0;
int rpm = 0;

void setup() { 
  Serial.begin(9600);
  digitalWrite(2, 1); //
  attachInterrupt(0, RPM, FALLING);
}

void loop() {
  Serial.println(rpm, DEC); // об/мин
}
void RPM (){
  rpm = (1000000/(micros() - micros1))*60;
  micros1 = micros();
}

Попробуйте и отпишитесь, что в сириал мониторе кажет

flying
Offline
Зарегистрирован: 12.11.2011

 Выводит 420 , что более похоже не правду.

maksim
Offline
Зарегистрирован: 12.02.2012

А если не секрет, где установлен двигатель и что он крутит?

maksim
Offline
Зарегистрирован: 12.02.2012

И еще, при таких низких оборотах нужна более высокая точность, добавьте к 1000000 точку и ноль 1000000.0

rpm = (1000000.0/(micros() - micros1))*60;

проверьте как сильно будут колебаться обороты при такой точности.

maksim
Offline
Зарегистрирован: 12.02.2012

ПИ регулятор:

#define RPMpin 2 // датчик Холла
#define PWMpin 5 // выход ШИМ на двигатель

int rpmzad = 3000; // заданное значение оборотов об/мин
float Kp = 0.2;    // коэф. усиления (пропорциональный)
float Ki = 0.1;    // коэф. усиления (интегральный)
int Ti = 100;      // время интегрирования в милисекундах

long micros1 = 0;
long millis1 = 0;
int rpm = 0; // текущие обороты об/мин
int P = 0;
int I = 0;

void setup() { 
  Serial.begin(9600);
  digitalWrite(RPMpin, 1); //
  attachInterrupt(0, RPM, FALLING);
  pinMode(PWMpin, OUTPUT);  
}

void loop() {
  if(micros()-micros1 > 500000){ // если обороты меньше 120 об/мин
    rpm = 0;                     // значит обороты равны 0 об/мин
  }
  P_reg();
  I_reg();
  int PI_reg = P + I;
  if(PI_reg > 255){ // ограничение по максимуму
    PI_reg = 255;
  }
  analogWrite(PWMpin, PI_reg);
  
  Serial.print("RPM = "); 
  Serial.print(rpm, DEC); // об/мин 
  Serial.print("  PWM = ");
  Serial.print(PI_reg, DEC);
  Serial.print("  P = ");
  Serial.print(P, DEC);
  Serial.print("  I = ");
  Serial.print(I, DEC);
  Serial.print('\n');
}

void RPM (){ // вычисление оборотов
  rpm = (1000000.0/(micros() - micros1))*60;
  micros1 = micros();
}

void P_reg(){ // пропорциональная составляющая
  P = Kp*(rpmzad - rpm);
  
  if(P < 0){ // ограничение по минимуму
    P = 0;
  }
}

void I_reg(){ // интегральная составляющая 
  //static long millis1;
  if(millis()-millis1 > Ti){
    if(rpmzad > rpm){
      I += Ki*(rpmzad - rpm);
    }
    if(rpmzad < rpm){
      I -= Ki*(rpm - rpmzad);
    }
    millis1 = millis();
  }
  
  if(I < 0){ // ограничение по минимуму
    I = 0;
  }
if(I > 255){ // ограничение по максимуму
    I = 255;
  }
}

у меня регулирует обороты маленького двигателя с ИК датчиком, при заданных 3000 об/мин выдает

RPM = 0       PWM = 255 P = 600 I = 255
RPM = 22     PWM = 255 P = 595 I = 255
RPM = 3096 PWM = 255 P = 0 I = 255
RPM = 4256 PWM = 255 P = 0 I = 255
RPM = 4718 PWM = 83   P = 0 I = 83
RPM = 4681 PWM = 83 P = 0 I = 83  
RPM = 4528 PWM = 83 P = 0 I = 83
RPM = 4379 PWM = 0 P = 0 I = 0
RPM = 3214 PWM = 0 P = 0 I = 0
RPM = 3038 PWM = 0 P = 0 I = 0
RPM = 2948 PWM = 15 P = 10 I = 5
RPM = 2768 PWM = 51 P = 46 I = 5
RPM = 2625 PWM = 80 P = 75 I = 5
RPM = 2594 PWM = 126 P = 81 I = 45
RPM = 2676 PWM = 109 P = 64 I = 45
RPM = 2814 PWM = 82 P = 37 I = 45
RPM = 2839 PWM = 93 P = 32 I = 61
RPM = 2851 PWM = 93 P = 32 I = 61
RPM = 2873 PWM = 88 P = 27 I = 61
RPM = 2876 PWM = 97 P = 24 I = 73
RPM = 2892 PWM = 94 P = 21 I = 73
RPM = 2918 PWM = 89 P = 16 I = 73
RPM = 2925 PWM = 95 P = 15 I = 80
RPM = 2938 PWM = 92 P = 12 I = 80
RPM = 2949 PWM = 90 P = 10 I = 80
RPM = 2953 PWM = 93 P = 9 I = 84
RPM = 2957 PWM = 92 P = 8 I = 84
RPM = 2967 PWM = 90 P = 6 I = 84
RPM = 2970 PWM = 93 P = 6 I = 87
RPM = 2975 PWM = 92 P = 5 I = 87
RPM = 2981 PWM = 90 P = 3 I = 87
RPM = 2980 PWM = 91 P = 3 I = 88
RPM = 2986 PWM = 91 P = 2 I = 89
RPM = 2991 PWM = 91 P = 1 I = 90
RPM = 2989 PWM = 93 P = 2 I = 91
RPM = 3239 PWM = 67 P = 0 I = 67
RPM = 2948 PWM = 77 P = 10 I = 67
RPM = 2892 PWM = 88 P = 21 I = 67
RPM = 2875 PWM = 103 P = 24 I = 79
RPM = 2909 PWM = 101 P = 22 I = 79
RPM = 2944 PWM = 93 P = 14 I = 79
RPM = 2951 PWM = 92 P = 9 I = 83
RPM = 2951 PWM = 96 P = 9 I = 87
RPM = 2973 PWM = 96 P = 6 I = 90
RPM = 2985 PWM = 94 P = 3 I = 91
RPM = 2984 PWM = 95 P = 3 I = 92
RPM = 2988 PWM = 94 P = 2 I = 92
RPM = 2989 PWM = 94 P = 2 I = 92
RPM = 2990 PWM = 93 P = 1 I = 92
RPM = 2988 PWM = 94 P = 2 I = 92
RPM = 2988 PWM = 95 P = 2 I = 93
RPM = 2992 PWM = 94 P = 1 I = 93
RPM = 2995 PWM = 94 P = 1 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93
RPM = 2995 PWM = 94 P = 1 I = 93
RPM = 2996 PWM = 93 P = 0 I = 93
RPM = 2995 PWM = 93 P = 0 I = 93
RPM = 2992 PWM = 94 P = 1 I = 93
RPM = 2992 PWM = 94 P = 1 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93
RPM = 2995 PWM = 94 P = 1 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93
RPM = 2997 PWM = 93 P = 0 I = 93

flying
Offline
Зарегистрирован: 12.11.2011

 Спасибо, попробую.

Двигатель стоит на самодельном токарном станке. Двигатель мощный 3КВт, но на низких оборотах не хватает мощности.