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

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

Уважаемые Гуру программирования для Ардуино, помогите пожалуйста разобраться вот с какой пробемой - у меня есть купленный из китая Ардуино УНО, есть оптический датчик (использую как датчик оборотов), блок реле (2 шт) и собственного производства PowerShield, питающий всю схему, плюс на нем разъемы для подключения дисплея, датчика, блока реле. Задача тривиальная - регистрируем обороты с помощью оптического датчика, если они отклоняются от заданных, подаем сигнал на реле, которое включает моторчик, передвигающий ползунок реасата, который в свою очередь изменяет скорость вращения двигателя. Вот код:

 #include <LiquidCrystal.h>

#define PIN_DO 2 // Установка контакта используемого в Arduino
LiquidCrystal lcd(8, 7, 9, 6, 4, 5); // (RS, E, DB4, DB5, DB6, DB7)
volatile unsigned int pulses;
float rpm;
unsigned long timeOld;
#define HOLES_DISC 4
#define RELE_UP 10
#define RELE_DOWN 11
unsigned int lock;
unsigned int t;
 
void setup()
{
 lcd.begin(16, 2);                  // Задаем размерность экрана
 //Serial.begin(9600);
 pinMode(PIN_DO, INPUT);
 pinMode(RELE_UP, OUTPUT);
 pinMode(RELE_DOWN, OUTPUT);
 t = 3; // время усреднения в секундах
 pulses = 0;
 timeOld = 0;
 lock = 0;
 digitalWrite(RELE_UP, HIGH);
 digitalWrite(RELE_DOWN, HIGH);
 rpm = 0;
}
 
void loop()
{
 if (digitalRead(PIN_DO) == HIGH && lock == 0)
 {
  pulses ++;
  lock = 1;
 }
 if (digitalRead(PIN_DO) == LOW) lock = 0;
 
 if (millis() - timeOld >= 1000 * t)
 {
 rpm = (pulses * 60) / (HOLES_DISC * t);
 
 Text();
 timeOld = millis();
 pulses = 0;
 }  
   if (rpm < 1300)
  {
  digitalWrite(RELE_UP, HIGH);
  digitalWrite(RELE_DOWN, HIGH);
  }
 else if ((rpm > 1300) && (rpm < 1500))
 {
  digitalWrite(RELE_DOWN, HIGH);
  delay(20);
  digitalWrite(RELE_UP, LOW);
 }
 else if ((rpm >= 1500) && (rpm <= 1505))
 {
  digitalWrite(RELE_UP, HIGH);
  digitalWrite(RELE_DOWN, HIGH);
 }
 else if (rpm > 1505)
 {
  digitalWrite(RELE_UP, HIGH);
  delay(20);
  digitalWrite(RELE_DOWN, LOW);
 }
}
 
void Text()
{
  lcd.clear();
  if (rpm < 1300)
  {    
    lcd.setCursor(1, 0);              // Устанавливаем курсор в начало 1 строки
    lcd.print("Zhdu oborotov");    
  }
  else if (rpm > 1300 && rpm < 1500)
  {
    lcd.setCursor(3, 0);
    lcd.print("RPM Low");  
  }
  else if (rpm >= 1500 && rpm <= 1505)
  {
    lcd.setCursor(3, 0);
    lcd.print("RPM Normal");
  }
  else if  (rpm > 1505)
  {
    lcd.setCursor(3, 0);
    lcd.print("RPM High");  
  }
 
  lcd.setCursor(2, 1);              // Устанавливаем курсор в начало 2 строки
  lcd.print(rpm, 0);         // Выводим текст
  lcd.setCursor(7, 1);
  lcd.print("ob/min");
}
 
Так вот, вроде работает, но как-то странно: в течении "времени усреднения" (t - в коде) реле получает питание  и на дисплее высвечивается то, что должно, а потом в течении того же времени снимается сигнал с реле, а на дисплее, обороты принимают случайные значения в пределах от 0 до 100. Не могу разобраться в чем дело.
Может проблема в китайском ардуино? 
yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

А вместо связки реле-моторчик-реостат, транзистор и ШИМ нельзя применить? Или мощность двигателя не позволяет.
А то эта связка каким-то электро-панком попахивает, но выглядит наверное довольно зрелещно.

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

Круто "реле-моторчик-реостат-мотор" :)

Sidorchuk
Offline
Зарегистрирован: 22.07.2016

Valera19701 пишет:

Круто "реле-моторчик-реостат-мотор" :)

Все куда как круче: "ардуино-реле-моторчик-реостат-мотор":)

 

Sidorchuk
Offline
Зарегистрирован: 22.07.2016

admiral_of_fleet пишет:

   if (rpm < 1300)

  {
  digitalWrite(RELE_UP, HIGH);
  digitalWrite(RELE_DOWN, HIGH);
.....
 }
 else if ((rpm >= 1500) && (rpm <= 1505))
 {
  digitalWrite(RELE_UP, HIGH);
  digitalWrite(RELE_DOWN, HIGH);
Может проблема в китайском ардуино? 

точно high должно быть? И вставьте код по-человечески, пожалуйста

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

Да, такая связка необходима, потому как последний моторчик в этой цепи на 7,5 кВт, соответственно реастат установлен в цепи параллельной обмотки возбуждения. Это что касается объекта управления. Реле действительно управляются сигналом низкого уровня. А вот как вставить код по человечески, немного не разобрался

Sidorchuk
Offline
Зарегистрирован: 22.07.2016

admiral_of_fleet пишет:

Уважаемые Гуру программирования  

Как-то пропустил этот момент, подумалось что ТС школьник, которому я в силах помочь. Ну да ладно, хотя бы тему апнул.

admiral_of_fleet пишет:

Реле действительно управляются сигналом низкого уровня.

Да это понятно. Логика странная по-моему.

 

Могу посоветовать Вам стандартную процедуру дебага - выводить переменные в последовательный порт. Pulses не переполняется? И еще рпм = 1300 выкинули из условий

http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii

 

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

Спасибо за совет, буду побывать различные варианты. Жаль, вот только, что программатор на плате спалил случайно.

Sidorchuk
Offline
Зарегистрирован: 22.07.2016

Еще могу порекомендовать использовать внешние прерывания для подсчета импульсов. volatile Вы для чего использовали? И delay лучше на заменить на millis 

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

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

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

#include <LiquidCrystal.h>
#define PIN_DO 2 // Установка контакта используемого в Arduino
LiquidCrystal lcd(8, 7, 9, 6, 4, 5); // (RS, E, DB4, DB5, DB6, DB7)
volatile unsigned int pulses;
float rpm;
unsigned long timeOld;
#define HOLES_DISC 4
#define RELE_UP 10
#define RELE_DOWN 11
unsigned int lock;
unsigned int t;
 
void setup()
{
 lcd.begin(16, 2);                  // Задаем размерность экрана
 //Serial.begin(9600);
 pinMode(PIN_DO, INPUT);
 pinMode(RELE_UP, OUTPUT);
 pinMode(RELE_DOWN, OUTPUT);
 t = 3; // время усреднения в секундах
 pulses = 0;
 timeOld = 0;
 lock = 0;
 digitalWrite(RELE_UP, HIGH);
 digitalWrite(RELE_DOWN, HIGH);
 rpm = 0;
}
 
void loop()
{
 if (digitalRead(PIN_DO) == HIGH && lock == 0)
 {
  pulses ++;
  lock = 1;
 }
 if (digitalRead(PIN_DO) == LOW) lock = 0;
 
 if (millis() - timeOld >= 1000 * t)
 {
 rpm = (pulses * 60) / (HOLES_DISC * t);
 //Serial.println(rpm);
 //if (rpm < 1300){Serial.println("Двигатель не управляется");}
 //else if (rpm > 1300 && rpm < 1500){Serial.println("Увеличиваю скорость");}
 //else if (rpm >= 1500 && rpm <= 1520){Serial.println("Все отлично!");}
 // else if  (rpm > 1520){Serial.println("Снижаю скорость");}

 Text();
 timeOld = millis();
 pulses = 0;
 }  
   if (rpm < 1300)
  {
  digitalWrite(RELE_UP, HIGH);
  digitalWrite(RELE_DOWN, HIGH);
  }
 else if ((rpm > 1300) && (rpm < 1500))
 {
  digitalWrite(RELE_DOWN, HIGH);
  delay(20);
  digitalWrite(RELE_UP, LOW);
 }
 else if ((rpm >= 1500) && (rpm <= 1505))
 {
  digitalWrite(RELE_UP, HIGH);
  digitalWrite(RELE_DOWN, HIGH);
 }
 else if (rpm > 1505)
 {
  digitalWrite(RELE_UP, HIGH);
  delay(20);
  digitalWrite(RELE_DOWN, LOW);
 }
}

void Text()
{
  lcd.clear();
  if (rpm < 1300)
  {    
    lcd.setCursor(1, 0);              // Устанавливаем курсор в начало 1 строки
    lcd.print("Zhdu oborotov");    
  }
  else if (rpm > 1300 && rpm < 1500)
  {
    lcd.setCursor(3, 0);
    lcd.print("RPM Low");  
  }
  else if (rpm >= 1500 && rpm <= 1505)
  {
    lcd.setCursor(3, 0);
    lcd.print("RPM Normal");
  }
  else if  (rpm > 1505)
  {
    lcd.setCursor(3, 0);
    lcd.print("RPM High");  
  }

  lcd.setCursor(2, 1);              // Устанавливаем курсор в начало 2 строки
  lcd.print(rpm, 0);         // Выводим текст
  lcd.setCursor(7, 1);
  lcd.print("ob/min");
}

 

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

Код в человеческом виде :)

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

Да, вот еще....
Когда реле не срабатывают, т.е. с оборотами все Ок, на дисплее всякая ересь не вылезает. Т.е. могу сделать вывод, что возможно какой-то косяк происходит при работе реле. Переменная rpm, такое ощущение, принимает случайное значение от 0 до 100, и конечно же реле отключаются. Вот только в коде у меня нет даже места, где бы я обнулял это значение

arduinec
Offline
Зарегистрирован: 01.09.2015

admiral_of_fleet пишет:

Переменная rpm, такое ощущение, принимает случайное значение от 0 до 100, и конечно же реле отключаются. Вот только в коде у меня нет даже места, где бы я обнулял это значение

pulses = 0;

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

admiral_of_fleet пишет:

Код в человеческом виде :)

до нормального ему еще далекова=то. Но переписивать мне облом.

Гриша
Offline
Зарегистрирован: 27.04.2014

admiral_of_fleet пишет:
Жаль, вот только, что программатор на плате спалил случайно.

заказывайте с запасом, это не последний трупик :))))

admiral_of_fleet пишет:
  есть оптический датчик (использую как датчик оборотов)

уверены, что помехи ему не мешают???  энкодеры  штука капризная, навык нужен.

ИМХО. код полная шляпа  -  в лупе два  digitalRead(PIN_DO), а потом работа с  релюхами,  да еще delay вешает контроллер периодически.  Определение  t=3 секунды ,за это время код в лупе проскакивает много раз и строки 47-72 исполняются много чаще чем требуется на определение влияния предыдущего воздействия.  релюхи, как и  Text();  необходимо засунуть перед строками 48-49  timeOld = millis();   pulses = 0; 

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

admiral_of_fleet пишет:
Да, такая связка необходима, потому как последний моторчик в этой цепи на 7,5 кВт, соответственно реастат установлен в цепи параллельной обмотки возбуждения. Это что касается объекта управления. Реле действительно управляются сигналом низкого уровня.

7,5 кВт - ни о чем , какой ток и напруга обмотки возбуждения???

и вообще  так писать (строки 31 и 36 ) очень глупо за это время состояние может измениться и оба неравенства будут не выполнены. для таких дел есть переменная boolean  i == 0 или i != 0  или byte

ЗЫ сперва измерьте, потом посчитайте, потом запишите, потом измените, потом обнулите и начните с начала.

admiral_of_fleet
Offline
Зарегистрирован: 26.01.2018

Спасибо большое за помощь, обязательно попробую реализовать данные мне рекомендации, вот только дождусь нового андурино

Kakmyc
Offline
Зарегистрирован: 15.01.2018

У тебя ток обмотки возбуждения пара ампер. Можно и без реостата неплохо его регулировать. Тем же igbt или мосфетом.