Регулятор оборотов двигателя с обратной связью

Joiner
Offline
Зарегистрирован: 04.09.2014

sany_sch пишет:

Joiner пишет:

Вывод - симистор хорошая штука для управления мощной нагрузкой.

Согласен. Но есть небольшие нюансы. Схема сложнее из за отслеживания нуля. скетч сложнее по тойже причине. А на мосфете используем встроенный ШИМ.

И самое важное. На постоенке двигатель мощнее.  А это хороший +.

Глубоко над этими вопросами пока не задумывался. Просто меня удивила простота и миниатюрность схемы регулятора размещенного в кнопке и регулирующая мощность 710 ватт. Там симистор, SMD кондерчик, SMD резистор, микроскопический динистор и переменник в виде двух полосок. А в кнопке которую я купил на замену и изломал, схема еще проще.

Будимир
Будимир аватар
Offline
Зарегистрирован: 04.02.2016

sany_sch пишет:

По этой статье http://cxem.net/arduino/arduino71.php собрал диммер.  схему слегка изменил:

Я со своим двигателем пока тоже затормазил. Схема схожая. Проблемы в том, что нужны стабильные низкие обороты. При датчике, который даёт 8 импульсов за оборот, достичть стабильности на низких оборотах сложно, нашёл опрический датчик с перфорацией на 36 отверстий по окружности. С 65 герцами париться не стоит, будет работать и на 50 я проверял.

Joiner
Offline
Зарегистрирован: 04.09.2014

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

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Как реализовать управление симистором без функции "Делей"?

Грузит всё особенно на малых оборотах.

01{
02  // Firing angle calculation : 1 full 50Hz wave =1/50=20ms
03  // Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle) For 60Hz => 8.33ms
04  // 10ms=10000us
05  // (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
06  int dimtime = (75*dimming);    // For 60Hz =>65   
07  delayMicroseconds(dimtime);    // Off cycle
08  digitalWrite(AC_LOAD, HIGH);   // triac firing
09  delayMicroseconds(10);         // triac On propogation delay (for 60Hz use 8.33)
10  digitalWrite(AC_LOAD, LOW);    // triac Off
11}

 

Будимир
Будимир аватар
Offline
Зарегистрирован: 04.02.2016

sany_sch пишет:

Как реализовать управление симистором без функции "Делей"?

у меня такой код без делая. поковыряйся может поможет:

001// TRIAC
002#define triac_control 12 // Triac control - pin
003#define open_loop 13 // open loop control (no PID)
004//RPM control
005#define sensorPin A1 // potentiometer or MACH3 - pin
006 
007//Power
008#define powerOn 4 // manual motor switch - pin
009 
010//Zero Detect
011#define zero_detect 2 //Zero detect - pin
012// when using values in the main routine and IRQ routine must be volatile value
013volatile byte zero_byte = LOW; // declare IRQ flag
014// HIGH = 1, LOW = 0
015 
016// HALL SENSOR
017#define hallsensor 3 // hall or optical sensor pin
018#define hallsensor2 A4 // to check signal on hall or optical sensor pin
019unsigned int rpmcount;
020unsigned int rpm;
021unsigned long timeold;
022unsigned long time1;
023 
024//LCD
025//LiquidCrystal::LiquidCrystal(rs, enable, d0, d1, d2, d3)
026#include <Wire.h>
027#include <LiquidCrystal.h>
028LiquidCrystal lcd(5, 6, 7, 8, 9, 10);
029 
030//INTERRUPT
031#include <avr/io.h>
032#include <avr/interrupt.h>
033#define PULSE 24 // pulse length on triac control pin
034//in timer cycles (1/64 prescalar=> 4us per cycle=>96us)
035// PID
036#include <PID_v1.h>
037 
038//Define Variables we'll be connecting to
039double Setpoint, Input, Output;
040 
041//Define the aggressive and conservative Tuning Parameters
042//double consKp=4, consKi=0.2, consKd=1;
043//double consKp=0.4, consKi=0.001, consKd=1;
044//double consKp=4, consKi=0.2, consKd=1;
045//double consKp=1, consKi=0.4, consKd=0.01; //100% work
046//double consKp=0.4, consKi=0.001, consKd=1;
047double consKp=1, consKi=0.4, consKd=0.01;
048 
049//Specify the links and initial tuning parameters
050PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
051int sensorValue=0;
052unsigned int analogValue=0;
053unsigned int delayValue=8000;
054unsigned int rpmmin = 6000; // Minimum and max rpm for the motor
055unsigned int rpmmax = 35000;
056unsigned int analogmin = 1; // analogmin and analogmax are the range of delay
057unsigned int analogmax = 1023;// time and fot each motor must be determined empirically
058 
059void setup() {
060 
061//Triac control setup
062pinMode(triac_control, OUTPUT);
063digitalWrite(triac_control, 0); // triac and LED off
064pinMode(open_loop, INPUT);
065digitalWrite(open_loop, 1);
066//Power switch
067pinMode(powerOn, INPUT);
068digitalWrite(powerOn, 1); // pull up on
069//Zero detect
070pinMode(zero_detect, INPUT);
071digitalWrite(zero_detect, 1); // pull up on
072attachInterrupt(0, zero_fun, FALLING); // interrupt 0 digital pin 2 connected ZC circuit
073// Hall sensor
074pinMode(hallsensor2, INPUT);
075pinMode(hallsensor, INPUT);
076digitalWrite(hallsensor, 1); // pull up on
077attachInterrupt(1, rpm_fun, FALLING); // interrupt 1 digital pin 3 connected hall sensor
078rpmcount = 0;
079rpm = 0;
080timeold = 0;
081// LCD detect
082lcd.begin(16,2); // initialize the lcd
083lcd.home (); // go home
084lcd.print(" Hello ");
085lcd.setCursor ( 0, 1 ); // go to the next line
086lcd.print (" GOOD LUCK ");
087delay(1000);
088lcd.clear();
089 
090// set up TIMER1
091OCR1A = 100; //initialize the comparator
092TIMSK1 = 0x03; //enable comparator A and overflow interrupts
093TCCR1A = 0x00; //timer control registers set for
094TCCR1B = 0x00; //normal operation, timer disabled
095// Serial.begin(9600);
096//PID
097Input = rpm;
098Setpoint = analogValue;
099//turn the PID on
100myPID.SetMode(AUTOMATIC);
101myPID.SetOutputLimits(analogmin,analogmax); //usage of this parameters instead of
102// rpmmin and rpmmax lets use only one mapping
103// in PID
104}
105void loop()
106{
107//motor switch and indicator = ON/OFF
108if (!digitalRead(powerOn)) // manual or by PC
109{
110// digitalWrite(powerIndicator, 1);
111zero_byte=HIGH;
112 
113///////////////RPM counter ///////////////////
114//////////////////////////////////////////////////////////////
115if ((millis()-timeold) >= 250)
116{
117//Update RPM every 250 millis, increase this for better RPM resolution,
118//decrease for faster update
119//rpm = 60*1000/(millis() - timeold)*rpmcount;
120unsigned long time = millis() - timeold;
121float time_in_sec = (float)time / 1000;
122float impuls_time = (float)rpmcount / time_in_sec;
123rpm = (int)impuls_time*60;
124rpmcount = 0; //reset
125timeold = millis(); //reset time
126 
127}
128//#######################PID ###############################
129//##########################################################
130analogValue = analogRead(sensorPin);
131int analogLevel = map(analogValue,23,833, analogmin,analogmax);
132//here we convert the voltage on pot to delay value
133// 23-833 is the range of voltages that I got from my pot (in 0-1023 scale)
134analogValue = analogLevel;
135 
136if (digitalRead(open_loop)==1)
137{ Input = map(rpm, rpmmin,rpmmax,analogmin,analogmax);
138// Here we put correspondance between rpm and delay values)
139Setpoint = analogValue;
140myPID.Compute();
141analogValue = Output;
142}
143analogValue = analogmax-analogValue+analogmin;
144// this inverts the delay values- higher rpm corrsponds to shorter delay times.
145if (analogValue > analogmax)
146{analogValue = analogmax;}
147if (analogValue < analogmin)
148{analogValue = analogmin;}
149delayValue=analogValue; // we need this as during a cycle of PID
150//calculations analogvalue changes several times
151//??????????????????TRIAC delay control ???????????????????
152 
153OCR1A = delayValue/4;
154 
155//**************indicator ************************
156 
157if (rpm < 10)
158{
159lcd.setCursor ( 0, 0 );
160lcd.print(" ");
161lcd.print (rpm);}
162if (10<= rpm && rpm < 100)
163{
164lcd.setCursor ( 0, 0 );
165lcd.print(" ");
166lcd.print (rpm);}
167if (100<= rpm &&rpm < 1000)
168{
169lcd.setCursor ( 0, 0 );
170lcd.print(" ");
171lcd.print (rpm); }
172if (1000<= rpm && rpm < 10000)
173{
174lcd.setCursor ( 0, 0 );
175lcd.print(" ");
176lcd.print (rpm);
177}
178if (10000<= rpm)
179{
180lcd.setCursor ( 0, 0 );
181lcd.print (rpm);}
182lcd.setCursor ( 7, 0 );
183lcd.print ("RPM");
184//////// output power indicator ///////////////////////////////
185// max power 13 bars min power bars
186lcd.setCursor ( 0, 1 );
187lcd.print(" ");
188lcd.setCursor ( 0, 1 );
189int Level = map(delayValue,analogmin,analogmax, 13, 0);
190// if the array element's index is less than ledLevel,
191// turn the pin for this element on:
192for (int bar = 0; bar < 13; bar++)  {
193if (bar < Level)  {lcd.print(0);}
194 }
195}
196else
197// when motor is OFF, the display allows to check the input of Hall sensor
198//(or optical level)
199{
200// digitalWrite(powerIndicator, 0);
201zero_byte=LOW;
202if (millis()-time1 >=10)
203{ sensorValue = analogRead(hallsensor2);
204//lcd.setCursor ( 0, 1 );
205//lcd.print(" ");
206lcd.clear();
207lcd.setCursor ( 0, 1 );
208int sensLevel = map(sensorValue,20,1000, 0, 13);
209// values 20,1000 is the output voltage range of sensor in 0-1023 scale (0-5V),
210// change them according to your sensor's output
211for (int sbar = 0; sbar < 13; sbar++)  {
212if (sbar < sensLevel)  { lcd.print(0);}
213}
214time1=millis();
215}
216}
217} // end of loop
218//Interrupt Service Routines
219 
220ISR(TIMER1_COMPA_vect) //comparator match
221{ digitalWrite(triac_control, 1); //triac on;
222TCNT1 = 65536-PULSE; //trigger pulse width = PULSE
223}
224ISR(TIMER1_OVF_vect) //timer1 overflow
225{
226digitalWrite(triac_control, 0); //turn off triac gate
227TCCR1B = 0x00; //disable timer stop unintended triggers
228}
229 
230void zero_fun() //zero detect
231{if (zero_byte)
232{ TCCR1B=0x03; //start timer with divide by 64 input
233TCNT1 = 0; //reset timer - count from zero
234}
235}
236 
237void rpm_fun()
238{
239rpmcount++;
240//Each rotation, this interrupt function is run
241}

 

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Будимир пишет:

у меня такой код без делая. поковыряйся может поможет:

Спасибо. "ковырялся" и так, и с переводчиком....

Вобщем мозгов у меня не хватило. Даже не до конца понял что куда подключать.  Буду признатеен если пояснишь на "великом и могучем".

Но методом проб и ошибок написл своё.

потенциометр на А0,   Холл на пин 8 ,    Зерро на пин 2,  управление симистором на пин 3.  Дисплей - 4,5,6,7,9,10

Дал 0,5 процента погрешности в каждую сторону от требуемых оборотов.   С 1000 об /мин   держит вполне сносно. Дальше - лучше.   Понимаю, что очень коряво, но довольный как удав.

Пока без всяких "плюшек".  на экран вывел время задержки от нуля,  нужные обороты от потенциометра, паследние показания оборотов датчика и средние обороты.  Хотя средние не очень нравятся. На мой взгляд ошибочны.

001#include <LiquidCrystal.h>      // библиотека экрана
002 
003LiquidCrystal lcd( 4, 5, 6, 7,9,10);   // пины экрана
004 
005int AC_LOAD = 3;    // пин управления симистором
006 
007volatile int dimming = 130;  // время задержки от нуля   7 = максимально, 128 = минимально
008volatile int i = 0;          // переменная для уменьшения времени задержки.
009 
010volatile unsigned long time; // время в микросекундах срабатывания датчика нуля
011unsigned long tims;           // переменная показаний времени
012        
013unsigned long currentTime;     //временные переменные для таймера экрана
014unsigned long loopTime;
015 
016int obMax = 8000;         //ввести максимальные обороты
017int obMin = 200;          //ввести минимальные обороты
018float kImp = 12;          //ввести кол-во импульсов на 1 оборот
019 
020volatile int holl = 0;    //переменная  срабатываня датчика
021volatile int prOb = 0;   //предвар реальн обороты
022volatile int rOb = 0;    // реальные обороты
023 
024volatile int zicls = 0;         // кол-во циклов для средних оборотов.
025volatile unsigned long sp = 0;           //переменная суммы оборотов/мин.
026 
027volatile unsigned int int_tic;    //переменные для подсчёта времени между импульсами.
028volatile unsigned long tic;
029 
030 
031void setup()
032{
033  pinMode(AC_LOAD, OUTPUT);        // назначаем выходом
034  attachInterrupt(0, zero_crosss_int, RISING);  // прерывание по пину 2
035    
036  lcd.begin(16, 2);          //дисплей 16символов 2строчки
037  lcd.setCursor(0,0);
038 
039lcd.write("R:");  //в верхней строке выводим время задержки
040 
041lcd.setCursor(0,1); 
042 
043lcd.write("t:");  // В нижней выводим показания датчика
044 
045 lcd.setCursor(7,0);
046 
047lcd.write("S:");  //в верхней строке будем выводить требуемые обороты
048 
049lcd.setCursor(7,1); 
050 
051lcd.write("S:");  // В нижней выводим фактичесские обороты
052 
053pinMode (8,INPUT); // вход сигнала ICP( №8 only для atmega328)
054//настройка 16 бит таймера-счётчика 1
055TCCR1B = 0; TCCR1A = 0; TCNT1 = 0;
056TIMSK1 = (1<<ICIE1)|(1<<TOIE1);//создавать прерывание от сигнала на пине ICP1
057TCCR1B = (1<<ICNC1)|(1<<ICES1)|(1<<CS10);//div 1
058}
059 
060ISR (TIMER1_CAPT_vect) { //прерывание захвата сигнала на входе ICP1
061tic= ((uint32_t)int_tic<<16)|TCNT1 ; //подсчёт тиков
062ICR1=0; int_tic=0; TCNT1=0;
063holl =holl+ 1;}   // после каждого срабатывания датчика холл+1
064 
065ISR (TIMER1_OVF_vect) { //прерывание для счёта по переполнению uint
066int_tic++; //считать переполнения через 65536 тактов
067if (int_tic > 50) {tic=0; int_tic=0;} //если на входе пусто более 1/5 секунды
068}                                                 //то обнулить счётчики
069 
070// the interrupt function must take no parameters and return nothing
071void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
072{
073  time = micros();
074   
075}
076 
077void loop()  {
078 
079   
080 int val = analogRead(A0);
081 int pR =map(val, 0, 1023, obMin, obMax); //Приводим показания регулятора к минимальным и максимальным оборотам
082  
083         prOb = 60000000/((tic * 0.0625 )*kImp);  //Высчитываем обороты по показаниям датчика
084         if( prOb >= 0){             //проверяем на соответствие.      
085           rOb = prOb ;              //если нормально, записываем в переменную
086           
087         }
088         else {}
089if (val > 0){                  //   если регулятор больше 0
090  if ( holl>=1){               // если сработал датчик
091     
092      
093          if ( rOb < ( pR-pR/200)){  //если реальные обороты меньше нужных - 0,5%
094            i= pR / rOb*3 ;          // просчитываем на сколько увеличим управление симистором.
095          i = constrain(i,1,5) ;     // ограничиваем результат от 1 до 5
096          dimming = dimming-i ;   //меняем время задержки на полученное значение
097                holl = 0;         // обнуляем срабатывание датчика
098             }
099          else {}
100           
101         if ( rOb >  ( pR+pR/200)){  //если реальные обороты больше нужнх + 0,5%
102           
103          dimming =dimming+10 ;   //  время задержки увеличиваем на 10
104          dimming = constrain(dimming,7,110) ;  // и ограничиваем от 7 до 110
105                holl = 0;     //  обнуляем срабатывание датчика.
106             }
107          else {}
108         }
109          else {}
110           
111       if (tic ==0){              // если двигатель не вращается
112           dimming = 100 ; //  время задержки = 100 подбираем опытным путём
113           }
114        else {}
115         
116       }
117    else {
118       dimming =130;      //Если регулятор на 0 то время задержки 130
119      }
120      
121    dimming = constrain(dimming,7,130) ; //  Следим чтоб время задержки было не меньше 7 и не больше 130
122    int dimtime = (75*dimming);    // For 60Hz =>65   
123    tims = micros();                           // считываем время, прошедшее с момента запуска программы
124  if(tims >= (time + dimtime)){       //если время больше или равно времени срабатывания нуля + время задержки
125   
126  digitalWrite(AC_LOAD, HIGH);   // открываем симистор
127  delayMicroseconds(10);         // задержка 10 микросекунд (для 60Hz = 8.33)
128  digitalWrite(AC_LOAD, LOW);    // выключаем сигнал на симистор.
129  }
130  else {}
131 
132    sp = sp + rOb;  //суммируем обороты для средних показаний
133    zicls = zicls + 1 ;     //считаем кол -во циклов
134     
135     
136      // Для вывода значений на дисплей 1 раз в секунду
137       
138   currentTime = millis();                           // считываем время, прошедшее с момента запуска программы
139  if(currentTime >= (loopTime + 1000)){              // сравниваем текущий таймер с переменной loopTime + 1 секунда
140     
141    lcd.setCursor(2,1);
142    lcd.print(prOb);  
143    lcd.print("  ");     // выводим показания датчика
144     
145    lcd.setCursor(2,0);
146    lcd.print(dimming);
147    lcd.print("  ");     // выводим время задержки на экран.
148 
149    lcd.setCursor(9,0);
150    lcd.print(pR);
151    lcd.print("       ");     // выводим нужные обороты на экран.
152     
153     lcd.setCursor(9,1);
154     
155lcd.print (sp/zicls);      // выводим средние обороты на экран.
156lcd.print("       ");
157 
158 
159sp = 0;           //обнуляем переменная суммы оборотов/мин.
160zicls = 0;        // обнуляем количество циклов.
161    loopTime = currentTime;                         // в loopTime записываем новое значение
162  }
163}

 

nevkon
Offline
Зарегистрирован: 20.01.2015

Посмотрите пожалуйста кто знает: http://www.mopedist.ru/blogs/raznye-poleznjashki/upravlenie-kolektornym-dvigatelem-u2010b.html

Правильно я понимаю что эта схема только для коллекторных двигателей работающих от АС напряжения или можно сделать и для ДС?

porshe
Offline
Зарегистрирован: 28.11.2016

Вот тут уже реализованный проект на ардуине с пид регулятором  http://bascom.at.ua/publ/simistornyj_pid_reguljator/1-1-0-128

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Снова приветствую всех участников темы, и всех с наступающими праздниками.

Появилось свободное врямя, и я снова вернулся к регулятору. Но что то у меня, впрочем как всегда, не идёт.

Решил подойти к вопросу с другой стороны.  Алгоритм такой: Есть нужные нам обороты, например 1000об\мин.  даём "зазор" например 5% в одну и в другую сторону. поручается  от 950 до 1050 об\мин.  Этот промежуток приравниваем к управлению симистором. 950 и ниже - полностью открыт, 1050 и выше - закрыт. Всё что в середине это промежуточные значения.  При таком алгоритме обороты должны стабилизироваться в этом диапазоне в зависимости от нагрузки.

Реализация , на мой взгляд, должна быть такая:

 float ko = pR/rOb;  //делим нужные нам обороты на реальные это коэфициент. если обороты равны, получаем 1, если реальные больше, то от 0 до 1. если меньше то от 1 и выше.  Нас интересует число с 4 цифры после запятой.
    long ai = ko * 10000;  //приводим коэфициент к целому положительному числу.
     int g =map(ai, 10500, 9500, 7, 130);  //задаём значение симистора от7-открыт до 130-закрыт   исходя из полученного числа.

Кажется, всё просто. но почему то не работает. Тоесть работает, но только без промежуточных значений. ВКЛ или ВЫКЛ.  Ошибка в самой первой строке. выводил значения на экран, либо 1, либо 0.  После запятой 00 и всё.  

Что не правильно?

nevkon
Offline
Зарегистрирован: 20.01.2015

Скорее всего pR и rOb являются целочисленными. В такой ситуации компилятор будет отдавать тоже целочисленные. Для перехода на дроби там нужно каккой-то толи префикс, то ли в конце что-то добавить. Еще не настолько хорошо знаю С.

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Спасибо. Но я уже сумел всё исправить и записал всё одной строкой.:

int g =map(rOb, pR*0.95, pR*1.05, ogr, 130);

Если обороты больше 1000, работает хорошо. А меньше - плохо. 

И рывки какието посторонние.

nevkon
Offline
Зарегистрирован: 20.01.2015

Здесь все зависит от дискретности датчика. Если у вас один такт на оборот (один датчик в месте по кругу вращения), то обратная связь может сильно запаздывать. Для более плавной регулировки на низких оборотах придется увеличить число датчиков для увеличения числа отсчетов. Бесконечно понижать число оборотов все равно не получится и думаю примерно на 400-500 оборотах в минуту наступит предел для понижения уже из-за импульсов ускорения и понижения мощности.

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

На один оборот приходится 12 импульсов. Уже не так мало. 400-500 об\мин. меня бы устроило.

nevkon
Offline
Зарегистрирован: 20.01.2015

Обороты считаются на каждом импульсе или усредненно по нескольким?

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

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Обороты считаем на каждом импульсе.

Симистор ограничен исходя из оборотов.

letaw
Offline
Зарегистрирован: 12.01.2017

Тоже интересна данная тема.

Есть шпиндель 300w 48В, ШИМ регулятор как на фото и инфракрасный датчик.

Разница наверное только в управлении скоростью по шим от 0 до 255.
Пока тестировал все процессы отдельно, все работает. Правда шпиндель через этот регулятор сильно свистит на неполных оборотах. 

P.s.: проблему свиста решил увеличением штатной частоты ШИМ ардуины

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

sany_sch пишет:

Обороты считаем на каждом импульсе.

Симистор ограничен исходя из оборотов.


Здравствуйте Александр, мне лень заходить на ютуб, поэтому напишу сюда.

Как-то приходилось ремонтировать центрифугу на старой работе, когда работал медтехником, там был тоже коллекторник на 220В, и рулил им мосфет, в целом аппарат был неплох, и работал долго, а попал он к нам, в мастерскую потому, что на датчике Холла окислом убился контакт...  Я это к чему, почему бы Вам не смотреть в сторону высоковольтного полевика и ШИМ? Это же занимает куда меньше ресурсов чем постоянно ждать переход через ноль и ещё добавлять задержку после него?

К стати, мой проект от части пересекается, на данный момент, с Вашим, но у меня не индуктивная нагрузка, пока что, но в планах есть замахнуться и на неё, просто пока что нету RC снабера, а от индуктивной нагрузки, в моём случае, симистор хаотично открывается когда надо и не надо.

P.S. Можно ускорить АЦП, пример тут https://geektimes.ru/post/255744/ тем самым поднять немного общую производительность.
P.P.S. Ешё можно не использовать много раз функцию lcd.print а формировать вывод при помощи sprintf_P http://arduino.ru/forum/programmirovanie/vyvod-na-lcd-teksta-i-dannykh-v-odnoi-stroke#comment-62647

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

HWman пишет:

Я это к чему, почему бы Вам не смотреть в сторону высоковольтного полевика и ШИМ?

Если почитаете тему с первой страницы, то именно так я и начинал.  Но мои полевики, почему то вылетали один за одним. Может нужен был более мощный, а может нужно было делать драйвер на управление. Незнаю. ответ я так и не нашел. Именно поэтому и перешел на симистор.

В общем, проблема в самом алгоритме стабилизации. Сейчас пробую разные варианты. Удалось снизить порог до 500об.мин.

За советы спасибо.  Буду пробовать.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Вот, мне нравится эта схемотехника:

(с) http://arduino.ru/forum/apparatnye-voprosy/upravlenie-tokarnym-stankom#comment-30941

Только главное частоту ШИМ не задерать выше 1к Гц, оптотрон может несправляться и полевику мало непокажется. Вообще в идеале 50-100 Гц.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

И к стати, у меня есть в мыслях возложить на отдельный контроллер фазовое управление, я ему буду только по юарт или АЦП подкидывать нужное значение 0-100%, а основной микроконтроллер будет делать всю остальную работу. 

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Схема примерно эта и была, только без опторазвязки.

 

HWman пишет:

И к стати, у меня есть в мыслях возложить на отдельный контроллер фазовое управление, я ему буду только по юарт или АЦП подкидывать нужное значение 0-100%, а основной микроконтроллер будет делать всю остальную работу. 

Думаю, это лишнее. И одна ардуинка справляется. 

Просто управлять симистором мы можем 100 раз в секунду,  а импульсов от датчика получаем на 200об\мин получаем всего 40

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

sany_sch пишет:

Схема примерно эта и была, только без опторазвязки.

Опторазвязка нужна, а вдруг что-то пойдёт не так и на затвор полевика пойдёт сетевое напряжение?

Если у Вас была похожая схемотехника странно что полевики вылетали, у центрифуги была похожая схемотехника, там на валу ещё был барабан для пробирок, за счёт этого двигатель останавливался около 20 секунд, и ничего, всё работало. Частоту ШИМ не изменяли? По умолчанию она довольно таки большая, оптотрон может не успевать на ней.

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

HWman]</p> <p>[quote=sany_sch пишет:

Если у Вас была похожая схемотехника странно что полевики вылетали, у центрифуги была похожая схемотехника, там на валу ещё был барабан для пробирок, за счёт этого двигатель останавливался около 20 секунд, и ничего, всё работало. Частоту ШИМ не изменяли? По умолчанию она довольно таки большая, оптотрон может не успевать на ней.

Частоту уменьшал. Вылетали при малейшей нагрузке на вал. Либо если разгон не плавный. Может слабый мосфет стоял? 10А

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

sany_sch пишет:

Думаю, это лишнее. И одна ардуинка справляется. 

Согласен, это быстрое решение, мне просто лень переписывать код на Си.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

sany_sch пишет:

Схема примерно эта и была, только без опторазвязки.

Вы же в курсе что ВВ полевику надо около 9-ти вольт на затвор чтобы тот полностью, а не частично, открывался?

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

HWman пишет:

sany_sch пишет:

Схема примерно эта и была, только без опторазвязки.

Вы же в курсе что ВВ полевику надо около 9-ти вольт на затвор чтобы тот полностью, а не частично, открывался?

Выбирал цифровой, чтоб 5 вольт на управлении.   10nk60zfp

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

sany_sch пишет:

Выбирал цифровой, чтоб 5 вольт на управлении.   10nk60zfp

Да, симмистор получается самый простой вариант, но ведь двигатель это индуктивная нагрузка, от неё симмистору будет не очень хорошо.

gena
Offline
Зарегистрирован: 04.11.2012

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

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

gena пишет:

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

Полностью с Вами солидарен, драйвер для полевика, особенно высоковольтного нужен 100% при варинте с ШИМ.
Мне кажется что надо юзать IRFP450 + IR2110 для таких целей как у Александра.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

А вот и то, о чём я говорил I2C диммер на базе ATtiny85
http://arduino.ru/forum/programmirovanie/attiny85-i-preryvanie#comment-2...

sany_sch
sany_sch аватар
Offline
Зарегистрирован: 19.01.2016

Вот некоторый результат на ПИД-регуляторе. может кто подскажет как правильно подобрать коэффициенты.

https://youtu.be/kf4bfDD_nDc

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Похоже вот так выглядит правильная регулировка при помощи ШИМ.

nevkon
Offline
Зарегистрирован: 20.01.2015

Эта схема практически ничем не отличается от той что вы привели несколькими постами выше. Добавлен только драйвер полевика и запитывается низковольтная часть от стабилитрона вместо батарейки. У меня по такой же схеме собрано, там обратной связью и не пахнет, на низких оборотах момента нету.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

nevkon пишет:

Эта схема практически ничем не отличается от той что вы привели несколькими постами выше. Добавлен только драйвер полевика и запитывается низковольтная часть от стабилитрона вместо батарейки. У меня по такой же схеме собрано, там обратной связью и не пахнет, на низких оборотах момента нету.


ОС можно прикрутить от таходатчика, а регулировку можно сделать плавнее, увеличив разрядность ШИМ, благо ардуина позволяет до целых 10 бит поднять, а это уже, внимание, 0..1023.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

И к тому же освободится немного ресурсов, вообщем ШИМ наше всё.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

При малых ШИМ никакое повышение его разрядности не добавить момента в мотор. Потому как ШИМ на моторе "интегрируется" и малые значения = малое напряжение на моторе => малый момент мотора. Нужна положительная обратная связь по току и аппаратная, а не "Ардуино".

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Есть библия по следящим электроприводам, она правда по аналоговым, но формульная часть присутствует везде

Logik
Offline
Зарегистрирован: 05.08.2014

Arhat109-2 пишет:

При малых ШИМ никакое повышение его разрядности не добавить момента в мотор. Потому как ШИМ на моторе "интегрируется" и малые значения = малое напряжение на моторе => малый момент мотора. 

Проблема не в " добавить момента" проблема в точности управления моментом при малых оборотах. И именно разрядность ШИМ тут ключевое. Другой вопрос, что значением ШИМ надо управлять грамотно, т.к. при одном и том же значении ШИМ возможно как медленое движение так и останов. Все потому, что момент трения покоя выше чем момент трения медленого движения. И тахометр, или аналогичное, как раз наилучшее решение проблемы.

 

 

Arhat109-2 пишет:

 Нужна положительная обратная связь по току и аппаратная, а не "Ардуино".

Это вобще нечто трансцендентное. Аппаратную ПОС(!!!) по току должны паять девственицы из бескислородной меди соблюдая направленость проводов.

ПС. Ликбез для использующих слово "момент". В установившемся режиме, т.е. при постоянном числе оборотов (в т.ч и равном 0) момент вращения равен моменту нагрузки. Это 3-ё закон Нютона для вращательного движения. Повышение момента вращения при постоянной нагрузке приводит к повышению числа оборотов и обратно. Момент нагрузки - штука тонкая, зависит от характера нагрузки. Для тележек момента трения покоя при 0 выше чем при малой скорости. Исходя из вышесказаного фразы типа "на низких оборотах момента нету" некоректны.

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

В аналоговых использовался тахометр )))

Logik
Offline
Зарегистрирован: 05.08.2014

Господа, о чем Вы?! Что за диспут аналоговый или цифровой на ардуине? При правильной реализации и одинаковой матмодели существенных различий нет. Про тахометр, так выше уже писано, нужен.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Решил поиграться с коллекторным двигателем, замутил на STM32F103 ШИМ в 20 кГц, слепил такую схемку, по классике жанра - из того что было под рукой, а полевиков логического уровня не было, тем более драйвера для обычных мосфетов, я же не буржуй, поэтому взял, старый добрый TIP122, выпаяный непомню откуда, непомню когда. Транзюк в целом неплох, фронты на входе конечно поровнее чем на выходе, но в целом справляется со своей задачей, тем более ток у меня небольшой, 0.1-0.2А, так как я замутил плавный пуск двигателя, типа этого, только транзюк не КТ827 а TIPок.

Тыкнул осциллом, и тут я кажется понял почему у Александра вылетали высоковольтные полевики - при напряжении питания в 36 В выбросы противоЭДС от движка, и диод HER302 уже не помогает, ничего удивительного, частота то большая.

Как можно увидеть на скрине осцилла, выбросы противоЭДС составляют почти в 2 раза больше напряжение, чем питалово, поэтому надо брать детали, с троекратным запасом.

З.Ы. Пробовал ещё ставить в разрыв по плюсу дроссель на 50 мкГ, испульсы противоЭДС пропадают, добавить кондюк, диод и будет DC-DCшка почти готовая.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

а диодом коллектор-эмиттер выходного зашунтировать не пробовали? (как в составном)

Logik
Offline
Зарегистрирован: 05.08.2014

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

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Возможно проблема в том, что компоненты у меня все БУ, но я проверил диод мультиметром, он адекватно "звониться".

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

ua6em пишет:

а диодом коллектор-эмиттер выходного зашунтировать не пробовали? (как в составном)


А зачем? Составной транзистор же имеет.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

sany_sch я Вам очень рекомендовал бы отказаться от симмисторного управления в пользу ШИМ, регулировка симмистором это всего лишь диапазон от 7 до 130, а ШИМ можно 0..1023, к тому же освободиться больше ресурсов микроконтроллера, потому как ШИМ аппаратный, минимум математики.

Главное разобраться почему у Вас вылетали транзисторы.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013
HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Он я у себя в группе даже опрос сделал по этому поводу. Большинство согласны что ШИМ лучше.

Zeyzey
Offline
Зарегистрирован: 04.04.2017

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

001int obMin = 200;          //ввести минимальные обороты
002int obMax = 9000;         //ввести максимальные обороты
003int kImp = 120;          //ввести кол-во импульсов на 10 оборотов
004int minzn = 115;           //  минимальное значение симмистора на котором начинается вращение.
005int ogrmin =  70 ;         // ограничение симистора на минимальных оборотах.
006int mindimming = 80;        //значение симистора при закллинившем станке (первоначальный импульс)
007int dopusk =  200 ;         //допуск оборотов в минус и плюс
008int razgon = 50;            //переменная разгона 1 - 100
009 
010 
011#include <LiquidCrystal.h>      // библиотека экрана
012 
013LiquidCrystal lcd( 9, 10, 4, 5, 6, 7); // пины экрана
014 
015int AC_LOAD = 3;    // пин управления симистором
016volatile int dimming = 130;  // время задержки от нуля   7 = максимально, 130 = минимально
017volatile unsigned long time; // время в микросекундах срабатывания датчика нуля
018unsigned long tims;           // переменная показаний времени
019 
020unsigned long currentTime;     //временные переменные для таймера экрана
021unsigned long loopTime;
022 
023int holl = 0;    //переменная  срабатываня датчика
024int pR;                  // показания регулятора
025int pRR;                // переменная для расчёта.
026int ogr ;                 //переменная ограничений симистора натекущих оборотах
027volatile int sp = 0;           //переменная суммы срабатываний датчика
028volatile int prOb ;   //предвар реальн обороты
029volatile int rOb ;    // реальные обороты
030 
031volatile unsigned int int_tic;    //переменные для подсчёта времени между импульсами.
032volatile unsigned long tic;
033volatile int t = 0;               //минимальное время импульсов +1
034int val ;
035void setup()
036{
037  pRR = obMin;
038  t = (15000 / ( obMin * (kImp / 10))) * 2; //высчитываем минимальное время импульсов +1
039  pinMode(AC_LOAD, OUTPUT);        // назначаем выходом
040  attachInterrupt(0, zero_crosss_int, RISING);  // прерывание по пину 2
041 
042  lcd.begin(16, 2);          //дисплей 16символов 2строчки
043  lcd.setCursor(0, 0);
044 
045  lcd.write("R:");  //в верхней строке выводим время задержки
046 
047  lcd.setCursor(0, 1);
048 
049  lcd.write("t:");  // В нижней выводим показания датчика
050 
051  lcd.setCursor(8, 0);
052 
053  lcd.write("S:");  //в верхней строке будем выводить требуемые обороты
054 
055  lcd.setCursor(8, 1);
056 
057  lcd.write("S:");  // В нижней выводим фактичесские обороты
058 
059 
060  pinMode (8, INPUT); // вход сигнала ICP( №8 only для atmega328)
061  //настройка 16 бит таймера-счётчика 1
062  TCCR1B = 0; TCCR1A = 0; TCNT1 = 0;
063  TIMSK1 = (1 << ICIE1) | (1 << TOIE1); //создавать прерывание от сигнала на пине ICP1
064  TCCR1B = (1 << ICNC1) | (1 << ICES1) | (1 << CS10); //div 1
065 
066}
067 
068ISR (TIMER1_CAPT_vect) { //прерывание захвата сигнала на входе ICP1
069  tic = ((uint32_t)int_tic << 16) | ICR1 ; //подсчёт тиков
070  ICR1 = 0; int_tic = 0; TCNT1 = 0;
071  sp = sp + 1 ; // для подсчёта оборотов в минуту.
072  holl = holl + 1;
073}   // после каждого срабатывания датчика холл+1
074 
075 
076ISR (TIMER1_OVF_vect) { //прерывание для счёта по переполнению uint
077  int_tic++; //считать переполнения через 65536 тактов
078  if (int_tic > t) {
079    tic = 0;  //если на входе пусто более минимального времени то обнулить счётчики
080    int_tic = 0;
081  }
082  if (int_tic > 500) {
083    dimming = 130; // если стоим 2 секунды, то сбрасываем напряжение.
084  }
085}
086 
087// the interrupt function must take no parameters and return nothing
088void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
089{
090  time = micros();
091 
092}
093 
094void loop()  {
095 
096 
097  val = analogRead(A0);
098  pR = map(val, 0, 1023, obMin, obMax); //Приводим показания регулятора к минимальным и максимальным оборотам
099 
100  if (val > 0) {                                       //   если регулятор больше 0
101    if ( holl >= 1) {                                  // если сработал датчик
102      prOb = 60000000 / ((tic * 0.0625 ) * kImp / 10); //Высчитываем обороты по показаниям датчика
103      if ( prOb >= 0) {                                //проверяем на соответствие.
104        rOb = prOb ;                                   //если нормально, записываем в реальные обороты
105 
106      }
107      if ( rOb < pR ) {                                //сверяем показания регулятора и реальные обороты
108        int fff = pR  - rOb;                           //узнаём разницу между оборотами
109        int pRu = map(fff, 1, obMax, 1, razgon);       //исходя из разницы и разгона высчитываем на сколько увеличить переменную для расчёта
110        pRR = pRR + pRu  ;                             //увеличиваем переменную расчёта
111      }
112      if ( pR < (rOb - 20) ) {                         //сверяем показания регулятора и реальные обороты
113        int fff = rOb - 20  - pR;                      //узнаём разницу между оборотами
114        int pRu = map(fff, 1, obMax, 1, razgon);       //исходя из разницы и разгона высчитываем на сколько уменьшить переменную для расчёта
115        pRR = pRR - pRu ;                              //увеличиваем переменную расчёта
116      }
117      pRR = constrain(pRR, (pR / 2), obMax);           //задаём пределы переменной для расчёта.
118      ogr = map(val, 0, 1023, ogrmin, 7);              //исходя из показаний регулятора узнаём на сколько может быть открыт симистор.
119       
120      dimming = map(rOb, (pRR - dopusk), (pRR + dopusk), ogr, minzn); //рассчитываем управление симистором.
121      holl = 0;                                                       // обнуляем срабатывание датчика
122    }
123     
124    if (tic == 0) {                                    // если двигатель не вращается
125      dimming = mindimming ;                          //  время задержки равно первоначальному импульсу
126    }
127    dimming = constrain(dimming, ogr, minzn) ;       //  Следим чтоб время задержки было не меньше ограничения и не больше минимального значения
128  }
129  else {
130    dimming = 130;                                   //Если регулятор на 0 то время задержки 130
131    pRR = obMin;
132  }
133 
134 
135  int dimtime = (75 * dimming);               // For 60Hz =>65
136  tims = micros();                            // считываем время, прошедшее с момента запуска программы
137  if (tims >= (time + dimtime)) {             //если время больше или равно времени срабатывания нуля + время задержки
138 
139    digitalWrite(AC_LOAD, HIGH);              // открываем симистор
140    delayMicroseconds(10);                   // задержка 10 микросекунд (для 60Hz = 8.33)
141    digitalWrite(AC_LOAD, LOW);              // выключаем сигнал на симистор.
142  }
143  else {}
144 
145 
146 
147 
148  // Для вывода значений на дисплей 2 раз в секунду
149 
150  currentTime = millis();                           // считываем время, прошедшее с момента запуска программы
151  if (currentTime >= (loopTime + 500)) {            // сравниваем текущий таймер с переменной loopTime + 0,5 секунд
152 
153    // выводим показания датчика
154 
155    lcd.setCursor(2, 0);
156    lcd.print(dimming );
157    lcd.print("  ");     // выводим время задержки на экран.
158 
159    lcd.setCursor(2, 1);
160    lcd.print(val );
161    lcd.print("  ");     // выводим нужные обороты на экран.
162 
163    lcd.setCursor(10, 0);
164    lcd.print(map(val, 0, 1023, obMin, obMax));
165    lcd.print("       ");     // выводим нужные обороты на экран.
166 
167    lcd.setCursor(10, 1);
168 
169    lcd.print (sp * (1200 / kImp)); // выводим средние обороты на экран.
170    lcd.print("       ");
171    sp = 0;
172    loopTime = currentTime;                         // в loopTime записываем новое значение
173  }
174}

 

Zeyzey
Offline
Зарегистрирован: 04.04.2017

Ладно попробую начать сам .Я так понимаю что основная проблемма это отсутствие у меги вывода модуля захата ICP1, остальные пины вроде как соответствуют пинам ардуины мини. Как можно реализовать эту функцию в меге??? Хочу сказать сразу что в програмировании я не сильно силен, но стремление огромное)