• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Управление оборотами вытяжного вентиялтора

Geremy

New member
Добрый день. Пытаюсь реализовать регулировку скорости вытяжного вентилятора, для этого использую:
1. Вентилятор ВЕНТС 100 Квайт
2. Диммер переменного тока
3. NodeMcu v3

Делаю как в этом видео (
), но только подключаю вентилятор. Использую вот этот скетч:
Код:
#include "hw_timer.h"         
const byte zcPin = 12;
const byte pwmPin = 13; 

byte fade = 1;
byte state = 1;
byte tarBrightness = 255;
byte curBrightness = 0;
byte zcState = 0; // 0 = ready; 1 = processing;
void setup() {
  Serial.begin(115200);  
  pinMode(zcPin, INPUT_PULLUP);
  pinMode(pwmPin, OUTPUT);
  attachInterrupt(zcPin, zcDetectISR, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  hw_timer_init(NMI_SOURCE, 0);
  hw_timer_set_func(dimTimerISR);
}

void loop() {
  // put your main code here, to run repeatedly:
    if (Serial.available()){
        int val = Serial.parseInt();
        if (val>0){
          tarBrightness =val;
          Serial.println(tarBrightness);
        }
       
    }
}


void dimTimerISR() {
    if (fade == 1) {
      if (curBrightness > tarBrightness || (state == 0 && curBrightness > 0)) {
        --curBrightness;
      }
      else if (curBrightness < tarBrightness && state == 1 && curBrightness < 255) {
        ++curBrightness;
      }
    }
    else {
      if (state == 1) {
        curBrightness = tarBrightness;
      }
      else {
        curBrightness = 0;
      }
    }
   
    if (curBrightness == 0) {
      state = 0;
      digitalWrite(pwmPin, 0);
    }
    else if (curBrightness == 255) {
      state = 1;
      digitalWrite(pwmPin, 1);
    }
    else {
      digitalWrite(pwmPin, 1);
    }
   
    zcState = 0;
}

void zcDetectISR() {
  if (zcState == 0) {
    zcState = 1;
 
    if (curBrightness < 255 && curBrightness > 0) {
      digitalWrite(pwmPin, 0);
     
      int dimDelay = 30 * (255 - curBrightness) + 400;//400
      hw_timer_arm(dimDelay);
    }
  }
}
Проблема в том, когда я понижаю напряжение на 50% , то вентилятор снижает обороты, но потом начинает непрерывно поднимать и снижать обороты. При этом я пару раз мерил напряжение на клеммах, оно доходило до 390В.

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

enjoynering

Well-known member
вместо

Код:
byte curBrightness = 0;
byte zcState = 0;
надо

Код:
volatile uint8_t curBrightness = 0;
volatile uint8_t  zcState = 0;
 

enjoynering

Well-known member
ну и в догонку правила для функций ISR

- the ISR function must take no parameters & return nothing
- delay() doesn't work during ISR & millis() doesn't increment
- declare all global variables inside ISR as "volatile", it prevent
compiler to make any optimization & unnecessary changes in the code
with the variable

функция, вызваемая прерыванием, функция должна быть без параметров и не возвращать значений. В англоязычной документации употребляется термин interrupt service routine для такой функции.
Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile.
 

Geremy

New member
вместо

Код:
byte curBrightness = 0;
byte zcState = 0;
надо

Код:
volatile uint8_t curBrightness = 0;
volatile uint8_t  zcState = 0;
Сделал - эффект тот же, вентилятор набирает и сбрасывает обороты.

Вот мой полный скетч:
Код:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#include "Timer.h"  // Замена стандартному delay

// ~~~ Для обновления по воздуху - BEGIN ~~~
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "hw_timer.h" //Либа для robodyn диммера

//Для robodyn диммера
const byte zcPin = 12;  // Zero-cross pin
const byte pwmPin = 13; // PWM pin
byte fade = 1;
byte state = 1;
volatile uint8_t tarDimmerVal = 255;
volatile uint8_t curDimmerVal = 0;
volatile uint8_t zcState = 0; // 0 = ready; 1 = processing;

const char* host = "esp8266-webupdate";

ESP8266WebServer server(80);

const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
// ~~~ Для обновления по воздуху - END ~~~

// ~~~ Чтобы избавиться от delay - BEGIN ~~~
Timer t;
// ~~~ Чтобы избавиться от delay - END ~~~

const char* ssid     = "ssid";
const char* password = "password";

const char* mqtt_server = "192.168.1.160";
const char* topicForSubscribe = "esp8266_wifi-dimmer-fan/cmnd/tarDimmerVal"; // Топик, который слушаем
WiFiClient espClient;
PubSubClient client(espClient);

char msgBufferPPM[10];          // буфер для отправки на MQTT сервет
String msg; // Переменная для отправки по MQTT

void setup() {
  Serial.println("Starting ...");
  Serial.begin(9600);

// ~~~ Dimmer BEGIN ~~~
  pinMode(zcPin, INPUT_PULLUP); //Инициализируем порт для zero-cross
  pinMode(pwmPin, OUTPUT);  //Инициализируем PWM (ШИМ)
  attachInterrupt(zcPin, zcDetectISR, RISING);    // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  hw_timer_init(NMI_SOURCE, 0);
  hw_timer_set_func(dimTimerISR);
// ~~~ Dimmer END ~~~

  // We start by connecting to a WiFi network
  wifi_station_set_hostname("WiFi_Dimmer_Fan"); // Задаем имя устройству
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
     would try to act as both a client and an access-point and could cause
     network-issues with your other WiFi-devices on your WiFi-network. */
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Инициализируем MQTT сервер
    client.setServer(mqtt_server, 1883);
    client.setCallback(callback);

  // ~~~ Настраиваем обновление по воздуху - BEGIN ~~~
  Serial.println();
  Serial.println("Booting Sketch...");
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() == WL_CONNECTED) {
    MDNS.begin(host);
    server.on("/", HTTP_GET, []() {
      server.sendHeader("Connection", "close");
      server.send(200, "text/html", serverIndex);
    });
    server.on("/update", HTTP_POST, []() {
      server.sendHeader("Connection", "close");
      server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
      ESP.restart();
    }, []() {
      HTTPUpload& upload = server.upload();
      if (upload.status == UPLOAD_FILE_START) {
        Serial.setDebugOutput(true);
        WiFiUDP::stopAll();
        Serial.printf("Update: %s\n", upload.filename.c_str());
        uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
        if (!Update.begin(maxSketchSpace)) { //start with max available size
          Update.printError(Serial);
        }
      } else if (upload.status == UPLOAD_FILE_WRITE) {
        if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
          Update.printError(Serial);
        }
      } else if (upload.status == UPLOAD_FILE_END) {
        if (Update.end(true)) { //true to set the size to the current progress
          Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
        } else {
          Update.printError(Serial);
        }
        Serial.setDebugOutput(false);
      }
      yield();
    });
    server.begin();
    MDNS.addService("http", "tcp", 80);

    Serial.printf("Ready! Open http://%s.local in your browser\n", host);
    Serial.print("If doesn't work, for update firmware go to " + WiFi.localIP());
   
  } else {
    Serial.println("WiFi Failed");
  }
  // ~~~ Настраиваем обновление по воздуху - END ~~~
 
  client.setCallback(callback);   // Для получения ответа по MQTT
  pinMode(2, OUTPUT); // Инициируем внутренний светодиод
  t.oscillate(2, 500, HIGH, 5); // Моргаем 5 раз встроенным светодиодом
}

void loop() {
if (!client.connected()) {
     delay(1000);
    reconnect();
  }
  client.loop();

  server.handleClient();  // Обрабатываем запрос с вебсерверу

  t.update();  // Необходимо для нормальной работы Timer
}

// Функция отправки значений диммера
void SendDimmerStatus(){
  msg = String(tarDimmerVal);
  msg.toCharArray(msgBufferPPM, msg.length()+1);
  client.publish("esp8266_wifi-dimmer-fan/dimmer/tarDimmerVal", msgBufferPPM); // отправляем в топик целевое значение диммера
  msg = String(curDimmerVal);
  msg.toCharArray(msgBufferPPM, msg.length()+1);
  client.publish("esp8266_wifi-dimmer-fan/dimmer/curDimmerVal", msgBufferPPM); // отправляем в топик текущее значение диммера
}

void reconnect(){
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      // client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe(topicForSubscribe);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

// Метод для получения сообщения по MQTT в Nodemcu
void callback(char *topic, byte *payload, unsigned int length) {  //payload - массиы byte (byte[])
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  String stringMsg; // Получаем сообщение в виде String
  for (int i = 0; i < length; i++) {
     stringMsg += (char)payload[i];
  }

  tarDimmerVal = stringMsg.toInt();
 
  Serial.print("tarDimmerVal - ");
  Serial.println(tarDimmerVal);

  stringMsg = "";

  if(sizeof(payload) > 1){  // Проверяем длину массива в байтах
    t.oscillate(2, 500, HIGH, 2); // Моргаем 5 раз встроенным светодиодом
    SendDimmerStatus(); // Отправляем данные
  }
}

// Метод для моргания
void blinks() {
  digitalWrite(2, HIGH);
  delay(500);
  digitalWrite(2, LOW);
  delay(500);
}

// Функция для WiFi диммера
void dimTimerISR() {
    if (fade == 1) {
      if (curDimmerVal > tarDimmerVal || (state == 0 && curDimmerVal > 0)) {
        --curDimmerVal;
      }
      else if (curDimmerVal < tarDimmerVal && state == 1 && curDimmerVal < 255) {
        ++curDimmerVal;
      }
    }
    else {
      if (state == 1) {
        curDimmerVal = tarDimmerVal;
      }
      else {
        curDimmerVal = 0;
      }
    }
   
    if (curDimmerVal == 0) {
      state = 0;
      digitalWrite(pwmPin, 0);
    }
    else if (curDimmerVal == 255) {
      state = 1;
      digitalWrite(pwmPin, 1);
    }
    else {
      digitalWrite(pwmPin, 1);
    }
   
    zcState = 0;
}

// Функция для WiFi диммера
void zcDetectISR() {
  if (zcState == 0) {
    zcState = 1;
 
    if (curDimmerVal < 255 && curDimmerVal > 0) {
      digitalWrite(pwmPin, 0);
     
      int dimDelay = 30 * (255 - curDimmerVal) + 400;//400
      hw_timer_arm(dimDelay);
    }
  }
}
 

nikolz

Well-known member
выложите лишь
1) функцию управления диммером с комментариями алгоритма
2) то место, где вы обращаетесь к ней
---------------
пока предположу что у вас задан режим изменение освещенности от мин до мах
вот вы и получаете
 

=AK=

New member
Добрый день. Пытаюсь реализовать регулировку скорости вытяжного вентилятора, для этого использую:
1. Вентилятор ВЕНТС 100 Квайт
2. Диммер переменного тока
3. NodeMcu v3

Делаю как в этом видео (...), но только подключаю вентилятор.
...
Подскажите как правильно настроить систему, чтобы вентилятор держал обороты?
То, что вы делаете, хорошо работать не может в принципе. Потому что мотор - это не лампочка:
  1. Лампочка - это резистивная нагрузка, а мотор представляет собой в основном индуктивную нагрузку. В конце полупериода сети, когда напряжение падает до нуля, ток в резистивной нагрузке тоже падает до нуля и симистор выключается. А в индуктивной нагрузке при нулевом напряжении в сети ток продолжает течь и симистор не выключается. Поэтому регулировки не получается, работа нестабильная.
  2. Скорость вращения асинхронного двигателя переменного тока мало зависит от напряжения питания. Она определяется частотой питающего напряжения. Даже если бы вам удалось заставить диммер работать правильно (например, использовав вместо симистора IGBT или MOSFET и сделав диммер с падающим фронтом, Trailing-edge Dimmer), то диапазон регулировки оборотов получился бы небольшим.
Стабильной работы обычного (т.е. нерегулируемого) асинхронного двигателя на меньших оборотах можно добиться если подавать на него питание с меньшей частотой, а не 50 Гц. В идеале - использовав инвертер, который будет синтезировать мотору синусоидальное напряжение питания заданной частоты и амплитуды.

В самом простом случае можно подать на мотор полупериод сети, затем выдержать паузу в один период сети, затем подать полупериод другой полярности, опять паузу в полный период, и т.д. Это обеспечит на моторе частоту питающего напряжения в 3 раза меньше чем 50 Гц, мотор будет вращаться в три раза медленнее. Однако вращение будет не совсем равномерным, а пульсирующим; будет ощущаться заметная вибрация, поскольку форма питающего напряжения будет не очень-то синусоидальная.
 

=AK=

New member
Файлопомойки для ликбеза малопригодны, они упускают из рассмотрения слишком многое. Еще раз, для тех, кому требуется ликбез: в общем виде, для неизвестно-какого-двигателя, управление скоростью путем регулировки напряжения не дает гарантированного хорошего результата. Оно дает более-менее удовлетворительный результат для двигателей с "мягкой" характеристикой, плохо годится для асинхронных двигателей с "жесткой" характеристикой, и совершенно непригодно для синхронных двигателей. Даже для двигателей с "мягкой" характеристикой, довольно трудно гарантировать старт при малом напряжении. Тогда как управление управление скоростью путем регулировки частоты питания годится для любого типа двигателя.
 

Geremy

New member
То, что вы делаете, хорошо работать не может в принципе. Потому что мотор - это не лампочка:
  1. Лампочка - это резистивная нагрузка, а мотор представляет собой в основном индуктивную нагрузку. В конце полупериода сети, когда напряжение падает до нуля, ток в резистивной нагрузке тоже падает до нуля и симистор выключается. А в индуктивной нагрузке при нулевом напряжении в сети ток продолжает течь и симистор не выключается. Поэтому регулировки не получается, работа нестабильная.
  2. Скорость вращения асинхронного двигателя переменного тока мало зависит от напряжения питания. Она определяется частотой питающего напряжения. Даже если бы вам удалось заставить диммер работать правильно (например, использовав вместо симистора IGBT или MOSFET и сделав диммер с падающим фронтом, Trailing-edge Dimmer), то диапазон регулировки оборотов получился бы небольшим.
Стабильной работы обычного (т.е. нерегулируемого) асинхронного двигателя на меньших оборотах можно добиться если подавать на него питание с меньшей частотой, а не 50 Гц. В идеале - использовав инвертер, который будет синтезировать мотору синусоидальное напряжение питания заданной частоты и амплитуды.

В самом простом случае можно подать на мотор полупериод сети, затем выдержать паузу в один период сети, затем подать полупериод другой полярности, опять паузу в полный период, и т.д. Это обеспечит на моторе частоту питающего напряжения в 3 раза меньше чем 50 Гц, мотор будет вращаться в три раза медленнее. Однако вращение будет не совсем равномерным, а пульсирующим; будет ощущаться заметная вибрация, поскольку форма питающего напряжения будет не очень-то синусоидальная.
Добрый день.
А можно ли как-то "допилить" заводские регуляторы скорости так чтобы они управлялись через NodeMcu?
Нашел например такие:
Регулятор скорости РС-1-300
Регулятор скорости РС-1-400

И еще вопрос - как узнать чем регулируется вентилятор напряжением или частотой?
 

Geremy

New member
Или может уже есть проверенные варианты вытяжного вентилятора + esp ?
 

CodeNameHawk

Moderator
Команда форума
Примените другой алгоритм, нп. минута работает, девять "отдыхает".
 

nikolz

Well-known member
Файлопомойки для ликбеза малопригодны, они упускают из рассмотрения слишком многое. Еще раз, для тех, кому требуется ликбез: в общем виде, для неизвестно-какого-двигателя, управление скоростью путем регулировки напряжения не дает гарантированного хорошего результата. Оно дает более-менее удовлетворительный результат для двигателей с "мягкой" характеристикой, плохо годится для асинхронных двигателей с "жесткой" характеристикой, и совершенно непригодно для синхронных двигателей. Даже для двигателей с "мягкой" характеристикой, довольно трудно гарантировать старт при малом напряжении. Тогда как управление управление скоростью путем регулировки частоты питания годится для любого типа двигателя.
Т е Вы согласились что напряжением можно управлять оборотами?
Но вместо ответа на вопрос автора темы (почему не едет велосипед) Вы предлагаете ему купить мотоцикл.
прикольно.
 

nikolz

Well-known member
Отвечу на вопрос как отличить устройство управление частотное от управление напряжением.
Все очень просто
Если устройство в маленькой коробочке весит менее 500 г и стоит менее 500 руб то оно для управление оборотами с помощью изменения напряжения.
Если устройство размером с планшет весит не менее кг стоит несколько тысяч рублей - то это частотник.
--------------------
Поэтому частотник имеет лучшие характеристики но для управления бытовыми системами вентиляции используют в основном управление оборотами путем изменения напряжения.
-----------------
 

=AK=

New member
Т е Вы согласились что напряжением можно управлять оборотами?
Но вместо ответа на вопрос автора темы (почему не едет велосипед) Вы предлагаете ему купить мотоцикл.
прикольно.
Вы ломитесь лбом об стенку потому что или не читаете чужие сообщения, или не понимаете смысл написанного. Еще раз: если ТС повезет и мотор у него с мягкой характеристикой, то он сможет удовлетворительно управлять мотором при помощи диммера с падающим фронтом. О чем мною было сказано еще до того, как вы получили ликбкез в интернете и поделились ссылками на него.
 

nikolz

Well-known member
Вы ломитесь лбом об стенку потому что или не читаете чужие сообщения, или не понимаете смысл написанного. Еще раз: если ТС повезет и мотор у него с мягкой характеристикой, то он сможет удовлетворительно управлять мотором при помощи диммера с падающим фронтом. О чем мною было сказано еще до того, как вы получили ликбкез в интернете и поделились ссылками на него.
А вы очевидно вообще не читаете тему.
Автор написал:
Проблема в том, когда я понижаю напряжение на 50% , то вентилятор снижает обороты, но потом начинает непрерывно поднимать и снижать обороты. При этом я пару раз мерил напряжение на клеммах, оно доходило до 390В.
т е ему уже повезло без ваших гаданий.
Поэтому вас и спрашивали что не правильно в конкретном решении
а не ваши известные из инета рассуждения
 

=AK=

New member
А вы очевидно вообще не читаете тему.
Автор написал:
Проблема в том, когда я понижаю напряжение на 50% , то вентилятор снижает обороты, но потом начинает непрерывно поднимать и снижать обороты. При этом я пару раз мерил напряжение на клеммах, оно доходило до 390В.
т е ему уже повезло без ваших гаданий.
Поэтому вас и спрашивали что не правильно в конкретном решении
а не ваши известные из инета рассуждения
Причины такого поведения вентилятора описаны в моем сообщении #6, п.1. Вы это сообщение или не читали, или не понимаете о чем там речь.
 

Geremy

New member
Есть небольшие новости. Я связался с производителем вентилятора и вот диалог 1 :
Я: Подскажите, можно ли регулировать скорость вентилятора ВЕНТС 100 Квайт путем регулирования подачи напряжения? Или нужно использовать регуляторы типа РС-1-300 и РС-1-400?
Производитель:
Здравствуйте!

Использовать РС-1-300.

диалог 2:
Я: Подскажите, можно ли регулировать скорость вентилятора ВЕНТС 100 Квайт путем регулирования подачи напряжения? Или нужно использовать регуляторы типа РС-1-300 и РС-1-400?
Представитель производителя: Да можно, любым симистром в пределах силы тока.
Я: Я использовал вот такой диммер (Диммер переменного тока AC 50/60Гц, 220B/110B, ШИМ (PWM), 1 канал, логика 3.3B/5B), но при понижении напряжения до 120В, вентилятор начинает работать на пониженных оборотных, но при этом он то набирает обороты, то их уменьшает, то есть нет работы на одних и тех же оборотах. Подскажите пожалуйста, можно ли использовать такой диммер?
Представитель производителя:
Ток у вентилятора 0,05А поэтому нужно максимально низкий ток.

В продаже обычно бывают 1А. Это лучше, чем 5А.

Возможно из-за этого и гуляют обороты.

Я связался с производителем диммера и он мне ответил:

Да, это вполне возможно. Вы можете увидеть пример здесь:
Paul RobotDyn on Instagram: “Testing our AC Light Dimmer on an 500 watt AC Motor #AC Light Dimmer #RobotDyn #potentiometer #Mega2560”

Что думаете есть шанс?
Сейчас вижу несколько путей:
1. Попытаться "дать ума" этому диммеру и заставить регулировать обороты
2. Приобрести частотник (собрать самому) и прикрутить его к ESP
3. Купить вытяжной вентилятор с регулировкой оборотов
4. Приобрести РС-1-300 и прикрутить к нему ESP
 

=AK=

New member
Отвечу на вопрос как отличить устройство управление частотное от управление напряжением.
Все очень просто
Если устройство в маленькой коробочке весит менее 500 г и стоит менее 500 руб то оно для управление оборотами с помощью изменения напряжения.
Если устройство размером с планшет весит не менее кг стоит несколько тысяч рублей - то это частотник.
--------------------
Поэтому частотник имеет лучшие характеристики но для управления бытовыми системами вентиляции используют в основном управление оборотами путем изменения напряжения.
-----------------
Ответ неверный. В конце моего сообщения №6 описано устройство частотного управления. Оно не универсально, зато его очень просто реализовать. В идеале для него лучше было бы использовать MOSFET или IGBT, однако и с симистором оно тоже вполне работоспособно. То есть, у ТС есть вс необходимое для реализации этого простейшего "частотника", который обеспечит или полную скорость, или 1/3 от полной скорости. Все сводится к написанию и отладке скетча. Советы ТС можно дать такие:
- оптосимистор надо открыть примерно через 0.5...1 мс после перехода сетевого через ноль
- оптосимистор надо держать открытым примерно 2...3 мс, после чего выключить
 
Сверху Снизу