Нерешаемо Однофазный асинхронный двигатель и arduino, управление скоростью вращения

Тема в разделе "Arduino & Shields", создана пользователем gkit, 11 июн 2020.

  1. gkit

    gkit Нуб

    Всем привет! Недавно нашёл однофазный асинхронный двигатель ( 220V 2KW ), и появилась задача контролировать его скорость, перерыл весь интернет и удивился, что подобным мало кто занимался, поэтому у меня есть пару вопросов.
    1. Получиться ли вообще управлять его скоростью с помощью Arduino? Или пытаться сделать на TL494 ?
    2. Как примерно будет выглядеть силовая часть, да и вообще схема в целом? В интернете довольно мало информации, в том числе и толковых схем.
    3. Что лучше всего использовать в качестве силового звена: MOSFET транзисторы, IGBT транзисторы или симисторы ? И какие примерно ?
    4. Нужен ли пусковой конденсатор ? Если да, то использовать формулу или любой воткнуть ?
    5. Почти весь базовый курс Arduino я изучил, написал самый простой код, подойдёт ли он ?
    Код (C++):

    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    #define MOTOR_PIN 6 // мотор! обязательно ШИМ выход!!!
    #define POT_PIN A0 // потенциометр
    #define MAX_SPEED 255 // максимальная скорость мотора, максимум 255
    #define DRIVER_VERSION 1    // 0 - маркировка драйвера дисплея кончается на 4АТ, 1 - на 4Т
    int pot_value = 0; // Тут храним значение потенциометра
    int motor_value = 0;
    int Speed_v_protsentax = 0; // Скорость в процентах выводим на дисплей
    uint32_t myTimer1; // Это таймер обновления дисплея, чтоб он не мельтишил

    // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------
    // Если кончается на 4Т - это 0х27. Если на 4АТ - 0х3f
    #if (DRIVER_VERSION == 1)
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    #else
    LiquidCrystal_I2C lcd(0x3f, 16, 2);
    #endif
    // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------

    void setup()
    {
    Serial.begin(9600);
      pinMode(POT_PIN, INPUT);
      pinMode(MOTOR_PIN, OUTPUT);
      lcd.init();
      lcd.backlight();
    Serial.println("setup!");
    lcd.setCursor(3,0);
      lcd.print("setup!");
      delay(2000);  
      lcd.clear();
      myTimer1 = millis();  // "сбросить" таймер
    }
    void loop()
    {    
    pot_value = analogRead(POT_PIN);
    motor_value =map(pot_value, 0, 1023, 0, MAX_SPEED);
    Speed_v_protsentax = round (map(pot_value, 0, 1023, 0, 100));
    motorTick();
    displeyTick();
    }

    void motorTick() {
    if(motor_value > 5){  // 5 потому что это для предотвращения дребезга потенциометра
      // Подаем наше трансформированное значение на вывод мотора MOTOR_PIN
      analogWrite(MOTOR_PIN, motor_value);
    }
    else {
      analogWrite(MOTOR_PIN, 0);
      }
    }
    void displeyTick() {
      if (millis() - myTimer1 >= 1000) {   // ищем разницу
        myTimer1 = millis();// сброс таймера
       lcd.setCursor(0,0);
      lcd.print("Speed:    %");
      lcd.setCursor(7,0);
      lcd.print(Speed_v_protsentax);
     
      }
    }
     
    6. Если уже кто-то занимался подобным, то можете пожалуйста скинуть исходники, буду благодарен.
    Всем спасибо за уделенное время.
     
  2. YDS

    YDS Нерд

    gkit нравится это.
  3. gkit

    gkit Нуб

    Спасибо за ответ, да, я видел эту статью, тиристорный регулятор мне не подходит, максимум его для болгарки использовать.
    Схема полного моста мне нравится, но я не понял как можно завязать управление с Arduino, в моем скетче используется один ШИМ выход, придется переписывать под 4 ?
    [​IMG]

    Также в интернете нашёл вот такую схему. Оригинальная статья: https://www.motor-r.info/p/blog-page_19.html
    upload_2020-6-12_12-15-21.png
    Но почему-то здесь номиналы деталей не полностью подписаны, сомневаюсь, что она работоспособна.
     
  4. gkit

    gkit Нуб

    Кстати, проблема пускового конденсатора решилась, он там встроенный был.
     
  5. parovoZZ

    parovoZZ Гуру

    Покрутить-то можно и фазным регулятором, но только сильно упадёт КПД, также обязательно снижать нагрузку на валу в соответствии со снижением действующего напряжения. Обязательно ставить внешний обдув обмоток. Иначе двигатель сгорит.
     
  6. parovoZZ

    parovoZZ Гуру

    Чувак! Ты в электронике вообще ни бум-бум? Схема для какой нагрузки?

    Ты вообще понимаешь, что такое поШИМить двухкиловаттное двигло? У тебя прогорит не только твоя схема, но ещё и папкин телевизор.
     
  7. gkit

    gkit Нуб

    Электроникой занимаюсь я два года. Схему я предложил как первую попавшуюся, чтоб узнать подойдёт ли она для меня и как примерно будет выглядеть схема в моём случае.
    Вообще выбить автоматы в моём гараже или в соседнем, да и вообще сгореть что-то не должно, как заявляет производитель максимальный ток у этой игрушки 13,9 А, грубо говоря 14 А. Жрать будет много - не спорю. Единственное что пусковой ток может превышать максимальный в два раза, создав большую просадку напряжения.
    Подробная инфа по двигателю: https://fastbox.su/dvigatel-elektriceskij-1-faznyj-22-kvt-2800r-kraft-230v-item-i8002880661.html
     
  8. gkit

    gkit Нуб

    Вот, может кому пригодится, написал скетч по примеру из интернета. Управление мотором по типу н-мост.
    Код (C++):
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    // 3 high, 1 high/PWM - rotation
    // 2 high, 4 high/PWM - reverse
    // 1 high, 4 high - brake

    #include "GyverTimer.h"   // подключаем библиотеку от известного Ютубера Алекса Гайвера

    // создаём таймеры в миллисекундах
    GTimer myTimer1(MS, 1000); // Это таймер чистки и обновления дисплея
    GTimer myTimer2(MS, 2000); // Для отладки. Выводим показания потенциометра в порт с указанным периодом

    #define DEADZONE 50  // "мёртвая зона" потенциометра

    #define DRIVER_VERSION 1    // 0 - маркировка драйвера дисплея кончается на 4АТ, 1 - на 4Т

    // пины драйвера, P1 и P4 должны быть на PWM пинах! (3, 5, 6, 9, 10, 11 для NANO и UNO)
    #define P1 3
    #define P2 4
    #define P3 5
    #define P4 6

    #define potPin A0      // сюда подключен потенциометр

    boolean switch_flag; // свитч флаг
    boolean mode1_flag = 0; //Флаг режима 1
    boolean mode2_flag = 0; //Флаг режима 2
    boolean mode3_flag = 0; //Флаг режима 3
    int potent, duty;
    int left_min, right_min;
    int Speed_1, Speed_2; // Скорости вращения вперед и назад
    int Speed_3 = 0; // Скорость в стоячем положении, логично = 0

    // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------
    // Если кончается на 4Т - это 0х27. Если на 4АТ - 0х3f
    #if (DRIVER_VERSION == 1)
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    #else
    LiquidCrystal_I2C lcd(0x3f, 16, 2);
    #endif
    // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------

    void setup() {
      // все пины драйвера как выходы, и сразу выключаем
      pinMode(P1, OUTPUT);
      digitalWrite(P1, 0);
      pinMode(P2, OUTPUT);
      digitalWrite(P2, 0);
      pinMode(P3, OUTPUT);
      digitalWrite(P3, 0);
      pinMode(P4, OUTPUT);
      digitalWrite(P4, 0);
      Serial.begin(9600);
      lcd.init();
      lcd.backlight();
    Serial.println("setup!");
    lcd.setCursor(4,0);
      lcd.print("SETUP!");
       
      left_min = 512 - DEADZONE;   // расчёт границ мёртвой зоны
      right_min = 512 + DEADZONE;  // расчёт границ мёртвой зоны

      delay(2000);
      lcd.clear();

    }

    void loop() {
      potent = analogRead(potPin);                    // читаем с потенциометра
      if (myTimer2.isReady())Serial.println(potent);
      if (potent > left_min && potent < right_min) {  // если мы в "мёртвой" зоне
        // вырубить все ключи
        digitalWrite(P1, 0);
        digitalWrite(P2, 0);
        digitalWrite(P3, 0);
        digitalWrite(P4, 0);
        switch_flag = 1;          // разрешить переключение
        mode1_flag = 1;
        mode2_flag = 0;
        mode3_flag = 0;
        DrawLCD();
      } else if (potent > right_min) {                // если мы вышли из мёртвой зоны справа
        if (switch_flag) {        // если разрешено переключение
          switch_flag = 0;        // запретить переключение
          digitalWrite(P2, 0);    // вырубить Р канальный второго плеча
          digitalWrite(P4, 0);    // вырубить N канальный второго плеча
          delayMicroseconds(5);   // задержечка на переключение на всякий случай
          digitalWrite(P3, 1);    // врубить Р канальный первого плеча
        }
        // рассчитать скважность для N канального первого плеча
        duty = map(potent, right_min, 1023, 0, 255);
        analogWrite(P1, duty);    // ЖАРИТЬ ШИМ!
      Speed_1 = map(potent, right_min, 1023, 1, 100);
       mode1_flag = 0;
        mode2_flag = 1;
        mode3_flag = 0;
      DrawLCD();

      } else if (potent < left_min) {                 // если мы вышли из мёртвой зоны слева
        if (switch_flag) {        // если разрешено переключение
          switch_flag = 0;        // запретить переключение
          digitalWrite(P3, 0);    // вырубить Р канальный первого плеча
          digitalWrite(P1, 0);    // вырубить N канальный первого плеча
          delayMicroseconds(5);   // задержечка на переключение на всякий случай
          digitalWrite(P2, 1);    // врубить Р канальный второго плеча
        }
        // рассчитать скважность для N канального второго плеча
        duty = map(potent, left_min, 0, 0, 255);
        analogWrite(P4, duty);    // ЖАРИТЬ ШИМ!
        Speed_2 = map(potent, 0, left_min, -100, -1);
        mode1_flag = 0;
        mode2_flag = 0;
        mode3_flag = 1;
        DrawLCD();
      }

    }

    void DrawLCD(){ // Костыльная функция отрисовки дисплея
      if (myTimer1.isReady()){
         lcd.clear(); // обновление экрана
      if (mode1_flag == 1){
         lcd.setCursor(0,0);
      lcd.print("Speed:     %");
      lcd.setCursor(0,1);
      lcd.print("-");     // Самая простая функция обновления дисплея
      lcd.setCursor(7,0);
      lcd.print(Speed_3);
      }

      else if (mode2_flag == 1){
    lcd.setCursor(0,0);
      lcd.print("Speed:     %");
       lcd.setCursor(0,1);
      lcd.print("FORWARD");
       lcd.setCursor(7,0);
      lcd.print(Speed_1);
      }
      else if (mode3_flag == 1){
        lcd.setCursor(0,0);
      lcd.print("Speed:     %");
       lcd.setCursor(0,1);
      lcd.print("BACKWARD");
      lcd.setCursor(7,0);
      lcd.print(Speed_2);
      }
        }
    }
     
    Последнее редактирование: 14 июн 2020
  9. b707

    b707 Гуру

    Проверяли?
    если верить комментариям в коде - должен сгореть при первом же включении
     
    parovoZZ нравится это.
  10. parovoZZ

    parovoZZ Гуру

    У нас здесь не викторина и не игра-угадайка, поэтому с таким подходом ничего, кроме стеба, не будет. Как и на другом любом техно-форуме.
     
  11. parovoZZ

    parovoZZ Гуру

    Серьезно??? Ты предлагаешь подать постоянный ток на двигатель переменного тока и говоришь, что ничего не сгорит? Никогда не видел, как горят электровозы-переменники, которые заехали под постоянку? Это при том, что переменка 25 кВ 50 Гц, а постоянка 3 кВ.
     
  12. parovoZZ

    parovoZZ Гуру

    Никому это не пригодится, т.к. для управления мостом надо брать МК, у которых таймеры специально предназначены для работы с мостом. Например, 261, 461, 861 attiny и новее. Все необходимые задержки (с учетом задержек в драйверах) они формируют аппаратно. Особенно это касается dead time, которые высчитываются исходя из характеристик применённых транзисторов.
     
    gkit нравится это.
  13. gkit

    gkit Нуб

    Извиняюсь, тупанул. Мотор то от переменки питается какой к черту диодный мост! В таком случае подскажите, получится ли у меня диммировать мотор симистором BTA41-800BRG на 40А 800В, если я буду использовать вот эту схему и скетч. По мощности этого симистора должно хватить.
    P = UI ==> 30 KW .
    upload_2020-6-14_22-35-7.png
    Код (C++):
    /*
       Диммер переменки на Arduino. Симистор через оптопару
       подключен к 4 пину, детектор нуля ко 2 пину.
       Переменная Dimmer - величина диммирования, от 0 до 255
    */

    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    #include "GyverTimer.h"   // подключаем библиотеку от известного Ютубера Алекса Гайвера

    // создаём таймеры в миллисекундах
    GTimer myTimer1(MS, 1000); // Это таймер чистки и обновления дисплея
    GTimer myTimer2(MS, 2000); // Для отладки. Выводим показания потенциометра в порт с указанным периодом

    #define DRIVER_VERSION 1    // 0 - маркировка драйвера дисплея кончается на 4АТ, 1 - на 4Т

    #define potPin A0      // сюда подключен потенциометр
    #define dimPin 4  // Пин диммирования
    #define zeroPin 2 // Здесь детектор 0

    #include <CyberLib.h> // шустрая библиотека для таймера

    volatile int tic, Dimmer;
    int Speed;
    int Val;

    // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------
    // Если кончается на 4Т - это 0х27. Если на 4АТ - 0х3f
    #if (DRIVER_VERSION == 1)
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    #else
    LiquidCrystal_I2C lcd(0x3f, 16, 2);
    #endif
    // -------- АВТОВЫБОР ОПРЕДЕЛЕНИЯ ДИСПЛЕЯ-------------

    void setup() {
      Serial.begin(9600);
      lcd.init();
      lcd.backlight();
      pinMode(potPin, INPUT);
      pinMode(dimPin, OUTPUT);
      digitalWrite(dimPin, 0);
      pinMode(zeroPin, INPUT);                 // настраиваем порт на вход для отслеживания прохождения сигнала через ноль
      attachInterrupt(0, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень

      StartTimer1(timer_interrupt, 40);        // время для одного разряда ШИМ
      StopTimer1();                            // остановить таймер

      Serial.println("Start");
    }

    void loop() {
    /*  Это для управления диммером через порт
      if (Serial.available()) {
        Dimmer = Serial.parseInt();
        Speed = map(Dimmer, 0, 255, 0, 100);
        Serial.println(Dimmer);
        DrawLCD();
      }
    */


        Val = analogRead(potPin);
       Dimmer = map(Val, 0, 1023, 240, 0);
       if (myTimer2.isReady())Serial.println(Val);
       Speed = map(Val, 0, 1023, 0, 100);
      DrawLCD();
      timer_interrupt();
      detect_up();
      detect_down();
    }

    //----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
    void timer_interrupt() {       // прерывания таймера срабатывают каждые 40 мкс
      tic++;                       // счетчик
      if (tic > Dimmer)            // если настало время включать ток
        digitalWrite(dimPin, 1);   // врубить ток
    }

    void  detect_up() {    // обработка внешнего прерывания на пересекание нуля снизу
      tic = 0;                                  // обнулить счетчик
      ResumeTimer1();                           // перезапустить таймер
      attachInterrupt(0, detect_down, RISING);  // перенастроить прерывание
    }

    void  detect_down() {  // обработка внешнего прерывания на пересекание нуля сверху
      tic = 0;                                  // обнулить счетчик
      StopTimer1();                             // остановить таймер
      digitalWrite(dimPin, 0);                  // вырубить ток
      attachInterrupt(0, detect_up, FALLING);   // перенастроить прерывание
    }
    //----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------

    void DrawLCD(){
      if (myTimer1.isReady()){
         lcd.clear(); // обновление экрана
         lcd.setCursor(0,0);
         lcd.print("Speed:     %");
         lcd.setCursor(7,0);
         lcd.print(Speed);
      }
    }
     
  14. parovoZZ

    parovoZZ Гуру

    Конденсаторные моторы никто не диммирует и частоту на них не крутят.
     
    gkit нравится это.
  15. parovoZZ

    parovoZZ Гуру

    Да, ещё - очень нежелательно использовать симисторы. Лучше два встречно-параллельных тиристора. У симистора разные углы открывания в разных квадрантах при одинаковом управляющем токе.
     
    gkit нравится это.
  16. Daniil

    Daniil Гуру

    Может лучше купить чрп?
     
  17. parovoZZ

    parovoZZ Гуру

    Однофазный? Для двигла с конденсаторным пуском? Можно модель этого чуда?
     
    Daniil нравится это.
  18. gkit

    gkit Нуб

    Эх, спасибо всем за помощь. Как я понял это скорее всего невозможно. Думаю в будущем попробую раздобыть трёхфазный электродвигатель. Попробую поплясать с ним, на мой взгляд там реализовать управление проще, т.к он работает на постоянном токе и силовая часть будет меньше, технологию изготовления силовой части стоит подсмотреть в китайских регуляторах оборотов для слабеньких бесколлекторных двигателей. Надеюсь к тому времени наберусь побольше опыта.
    upload_2020-6-16_0-6-39.png
     
  19. parovoZZ

    parovoZZ Гуру

    Полная каша в голове...
     
    b707 нравится это.
  20. b707

    b707 Гуру

    Если делать самому, то в принципе все возможно. Принцип тот же, как у трехфазного, но используем два канала вместо трех. На одну пару ключей подаем синусоиду. на другую - ШИМ 50% для эмуляции нейтрали.
    А что касается конденсаторного пуска - то это лишь означает. что диапазон регулировки будет небольшим, вблизи характеристик конденсатора
     
    gkit нравится это.