Предложили мне сделать прототип регулятора постоянных оборотов (РПО) для прототипа винта изменяемого шага (ВИШ) небольшого летательного аппарата (ЛА).

Что имеем:
ЛА — Аэропоракт А-27М, двигатель Rotax 912, прототип ВИШ с электрическим приводом.

Что требуется:
Изготовить прототип РПО, который должен уметь поддерживать заранее заданные обороты — 3 режима, иметь возможность в ручную управлять шагом винта, иметь индикаторы увеличения\уменьшения шага винта и индикаторы срабатывания концевых переключателей.



Задача РПО сводится к изменению угла установки лопастей (шаг винта) в зависимости от режима полета, таким образом, чтобы обороты винта всегда оставались постоянными. В зависимости от скорости горизонтального полета шаг винта меняется от ? мин. до ? макс. На взлетном режиме при нулевой горизонтальной скорости шаг винта минимален. По мере увеличения горизонтальной скорости угол атаки лопасти уменьшается (угол атаки на рисунке не показан, но он примерно равен ? мин.). Уменьшается сопротивление вращению — винт «облегчается». Обороты двигатель начинают возрастать, РПО увеличивает шаг винта, при этом увеличивается сопротивление вращению винта — винт «затяжеляется». Обороты двигатель падают. Так РПО поддерживает заданные обороты.



Изменение угла установки лопастей, производится при помощи электрического привода. Для принятия решения о том, в какую сторону, и с какой скоростью вращать эл. двигатель привода, нужно знать только дельту, между текущей скоростью и заданной. РПО будет стремиться удерживать дельту в диапазоне от -60 до 60. При отрицательной дельте — уменьшается угол установки лопасти, при положительной — увеличивается. В идеале РПО должен стремиться держать нулевое значение, но на практике это невозможно, по многим причинам.

Для большей эффективности, скорость изменения угла установки, изменяется:

если дельта больше |150| скорость «MAX» — максимальная
если дельта больше |60| скорость «MIN» — минимальна



За основу регулятора, была взят Arduino. Я не стал прибегать к технологии Shieldsbuilding, а просто взял голый микроконтроллер, и залил туда загрузчик от Arduino. Использовал альтернативный загрузчик из пакета optiboot. Стандартный загрузчик некорректно работает с watchdog.

В качестве силовой части была использована пара полумостов BTS7960. Это очень сильно с запасом, но поскольку я старался сделать по максимуму надежную схему, выбор пал на них. Сигнал тахометра берется штатный с двигателя, подключил через оптрон 6N137, светодиод D6, гасит импульсы обратной полярности. Датчик тока ACS712-05A, используется только для определения срабатывания концевых выключателей. Ручное управление установки шага винта, реализовано программно, это не очень хорошо, но для первого прототипа вполне сгодится. Переключатель выбора режима работы, на уровне электрической схемы реализован так, чтобы при всех неопределенных положениях (интервал между соседними секциями контактов), интерпретировался как — ручной режим.

Плата была изготовлена по технологии Oracal, двухсторонняя, мне так легче разводить. Элементы с монтажом в отверстия, активно использовались для перехода на другую сторону платы. Поскольку плата не сложная, разводку делал прямо в CorelDRAW. Рисовал линиями нужной толщины, затем превращал их в контур. Очень удобно рисовать по сетке, в режиме точек, с шагом 1.27мм, с включенной привязкой к сетке. Подготовленные контуры вырезал при помощи плоттера, на пленке Oracal. Монтажной пленкой перенес на заранее подготовленный текстолит. Немного кропотливой работы по удалению ненужных частей пленки, и плата готова к травлению. Далее все стандартно.

Корпус был изготовлен собственноручно владельцем ЛА, из листового полистирола толщиной 2мм. Для экранирования от помех, был обклеен алюминиевой фольгой и подключен к общему проводу.

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

Скетч:
#include <avr/wdt.h> // Подключаем библиотеку wdt

volatile unsigned long micros_prev = 0;  // Предидущее значение микросекунд
long rpm_sum = 0; // Сумма накопленых N значений оборотов
int rpm_val = 0; // Счетчик N
int rpm = 0; // Тахометр
int rpm_go = 0; // Заданные обороты
int rpm_select = 0; // Переключатель режимов
int rotor_left = 0; // Флаг вращения в лево
int rotor_right = 0; // Флаг вращения в право
int current = 0; // Датчик тока
int current_left = 0; // Флаг факта наличия вращения в лево
int current_right = 0; // Флаг факта наличия вращения в право

void setup() {
  wdt_disable(); // Отключаем wdt
  pinMode(2, INPUT); digitalWrite(2, HIGH); //  RPM Сигнал с тахометра и подтяжка к +
  pinMode(4, INPUT); // IS Ошибка драйвера (обработка сигнала не реализована)
  pinMode(7, INPUT); digitalWrite(7, HIGH); //  Step_down Малый шаг и подтяжка к +
  pinMode(8, INPUT); digitalWrite(8, HIGH); //  Step_up Большой шаги подтяжка к +
  pinMode(13, OUTPUT); // Светодиод - Ручной режим "красный"
  pinMode(3, OUTPUT); // INH Разрешить крутить эл.двигатель
  pinMode(5, OUTPUT); // IN 1-ый полумост
  pinMode(6, OUTPUT); // IN 2-ой полумост
  pinMode(12, OUTPUT); // Светодиод - Большой шаг "зеленый"
  pinMode(11, OUTPUT); // Светодиод - Малый шаг "зеленый"
  pinMode(10, OUTPUT); // Светодиод - Большой шаг отбойник "красный" упор
  pinMode(9, OUTPUT); // Светодиод - Малый шаг отбойник "красный" упор
  attachInterrupt(0, RPM_IN, FALLING); // Активируем внешнее прерывание
  wdt_enable (WDTO_2S); // Включаем wdt с интервалом 2 секунды
}

void loop() {
  wdt_reset(); // Сбрасывам счетчик wdt
  MODE();
  CURR();
  LED();
}

// Функция вращения в лево
void LEFT() {
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  digitalWrite(3, HIGH);
}

// Функция вращения в лево - скорость "MAX" (ШИМ)
void LEFT_MAX() {
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  analogWrite(3, 200);
}

// Функция вращения в лево - скорость "MIN" (ШИМ)
void LEFT_MIN() {
  digitalWrite(5, HIGH);
  digitalWrite(6, LOW);
  analogWrite(3, 120);
}

// Функция вращения в право
void RIGHT() {
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(3, HIGH);
}

// Функция вращения в право - скорость "MAX" (ШИМ)
void RIGHT_MAX() {
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  analogWrite(3, 200);
}

// Функция вращения в право - скорость "MIN" (ШИМ)
void RIGHT_MIN() {
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  analogWrite(3, 120);
}

// Функция остановки эл.двигателя с торможением
void STOP() {
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(3, HIGH);
}

// Функция ручного режима
void HAND() {
  if (digitalRead(7) == LOW) {
    LEFT(); // Крутим эл.двигатель в лево если нажата кнопка в лево
    rotor_left = 1;
  } else {
    rotor_left = 0;
  }
  if (digitalRead(8) == LOW) {
    RIGHT(); // Крутим эл.двигатель в право если нажата кнопка в право
    rotor_right = 1;
  } else {
    rotor_right = 0;
  }
  if (rotor_left == 0 && rotor_right == 0) {
    STOP(); // Остановка эл.двигателя если не нажата ни одна кнопка
  }
}

// Функция автоматического режима
void AUTO() {
  if ((micros() - micros_prev) > 1000000) {
    rpm = 0;
  }
  // Отработка вращения в лево
  if (rpm < rpm_go - 60) {
    if (rpm < rpm_go - 150) {
      LEFT_MAX ();
    } else {
      LEFT_MIN ();
    };
    rotor_left = 1;
  } else {
    rotor_left = 0;
  }
  // Отработка вращения в право
  if (rpm > rpm_go + 60) {
    if (rpm > rpm_go + 150) {
      RIGHT_MAX ();
    } else {
      RIGHT_MIN ();
    };
    rotor_right = 1;
  } else {
    rotor_right = 0;
  }
  // Отработка диапазона "stop"
  if (rotor_left == 0 && rotor_right == 0) {
    STOP();
  }
}

// Функция обработки переключателя режимов работы
void MODE() {
  rpm_select = analogRead(0);
  if (rpm_select < 100) {
    rpm_go = 0;  // Ручной режим
  } else {
    if (rpm_select > 800) {
      rpm_go = 5700; // Автоматический режим "Взлет/Посадка"
    } else {
      if (rpm_select > 450) {
        rpm_go = 5300; // Автоматический режим "Набор высоты"
      } else {
        rpm_go = 4600; // Автоматический режим "Круиз"
      }
    }
  }
  if (rpm_go == 0) {
    HAND ();
  } else {
    AUTO ();
  }
}

// Функция распознавания направления вращения эл.двигателя
void CURR() {
  for (int i = 0; i < 4; i++) {
    current = current + analogRead(1);
  }
  current = current / 5;
  if (current < 496) {
    current_left = 1;
  } else {
    current_left = 0;
  }
  if (current > 516) {
    current_right = 1;
  } else {
    current_right = 0;
  }
}

// Функция отработки светодиодов
void LED() {
  if (rpm_go == 0) {
    digitalWrite(13, HIGH); // Ручной режим
  } else {
    digitalWrite(13, LOW);
  }
  // Если эл.двигатель крутим в лево а вращения нет, то включаем красный светодиод "Малый шаг" упор
  if (rotor_left == 1 && current_left == 0) {
    digitalWrite(11, LOW);
    digitalWrite(9, HIGH);
  }
  // Если эл.двигатель крутим в лево, то включаем зеленый светодиод "Малый шаг"
  else {
    if (rotor_left == 1) {
      digitalWrite(11, HIGH);
      digitalWrite(9, LOW);
    }
    else {
      digitalWrite(11, LOW);
      digitalWrite(9, LOW);
    }
  }
  // Если эл.двигатель крутим в право а вращения нет, то включаем красный светодиод "Большой шаг" упор
  if (rotor_right == 1 && current_right == 0) {
    digitalWrite(12, LOW);
    digitalWrite(10, HIGH);
  }
  // Если эл.двигатель крутим в право, то включаем зеленый светодиод "Большой шаг"
  else {
    if (rotor_right == 1) {
      digitalWrite(12, HIGH);
      digitalWrite(10, LOW);
    }
    else {
      digitalWrite(12, LOW);
      digitalWrite(10, LOW);
    }
  }
}

// Функция обработки сигнала с тахометра с усреднением данных
void RPM_IN() {
  rpm_sum = rpm_sum + (60000000.0 / (micros() - micros_prev));
  micros_prev = micros(); rpm_val++;
  if (rpm_val >= 10) {
    rpm = rpm_sum / 10;
    rpm_sum = 0;
    rpm_val = 0;
  }
}

Комментарии (22)


  1. AIV_Electronics
    19.06.2015 19:07
    +5

    А в чём суть статьи? В чём научная новизна и практическая значимость? Какие проблемы автор героически преодолевал решая поставленную задачу? Очень уж не подробно обо всём написано.
    Найдётся крайне немного народа, кому нужен управляемый шаг винта. Уж очень тематика узкая и механика важнее электроники.


    1. gleb_l
      20.06.2015 22:30

      Это же не докторская диссертация, а рассказ об инженерном решении одной частной задачи — он не обязан быть ни научно-новым, ни широкоприменимым. Вполне себе хорошая статья имхо — заслуживает +1. Другой вопрос — сядете ли вы в arduino-controlled aircraft? Я лично крепко подумаю ;). Правда, если данная конкретная модель самолета способна взлететь в положении самого тяжелого винта с максимальным взлетным весом — то теоретически ардуино испортить ничего не сможет — так как продолжать полет или садиться самолет сможет и подавно на любом шаге


      1. Korogodin
        21.06.2015 12:08

        У меня arduino-controlled aircraft вызовет меньше подозрений, чем любая другая не сертифицированная самоделка. Ардуина проста, отработана, протестирована миллионами, а это только способствует увеличению надежности.


  1. Ocelot
    19.06.2015 22:04
    +1

    Вот этот кусок вызывает вопросы:

    rpm_sum = rpm_sum + (60000000.0 / (micros() - micros_prev));

    1) Если дернуть прерывание RPM_IN() быстро два раза подряд, вывалится деление на ноль?
    2) Что происходит при переполнении micros()? А это случается каждые 70 минут.


    1. RasselFast
      20.06.2015 02:22

      1) Нет.
      2) Условимся, что прерывание срабатывает каждые 10,000 микросекунд.
      Предположим что после переполнения:
      micros() == 5,000
      micros_prev==4,294,962,296
      Далее идет операция (micros() — micros_prev), в числах это будет: 5,000 — 4,294,962,296
      В рамках типа переменной unsigned long результат вычисления будет равен 10,000.

      Переполнение никак не повлияло на результат.


      1. jaiprakash
        20.06.2015 10:59
        +2

        И всё же нужно переписать строку с возможностью деления на 0. Это же авионика, а не мигание светодиодом на столе, тут всё должно быть по MISRA C, даже двух команд на строке нельзя:

        micros_prev = micros(); rpm_val++;

        Из кода я так и не понял откуда взялось micros(), приведён фрагмент программы?

        Хоть статья понравилась, выглядит странным использование ардуино (как софта) в таком ответственном изделии. Программа на чистом С почти ничем не будет отличаться от приведённого скетча, за исключением полного контроля за происходящим. А так — остаётся элемент магии.


        1. NikitaKA
          20.06.2015 12:22

          откуда взялось micros()

          Это вшитая функция, есть еще millis(), например.


        1. RasselFast
          20.06.2015 17:10

          Подкорректировал функцию обработки прерывания. Теперь работать будет быстрее, и на 0 делить возможности не будет.

          // Функция обработки сигнала с тахометра с усреднением данных
          void RPM_IN() {
            rpm_sum = rpm_sum + (micros() - micros_prev);
            micros_prev = micros(); 
            rpm_val++;
            if (rpm_val >= 10) {
              rpm = 600000000 / rpm_sum;
              rpm_sum = 0;
              rpm_val = 0;
            }
          }
          

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


          1. jaiprakash
            20.06.2015 17:48

            Может arduino не поддерживает, но в С обычно пишут так (труднее ошибиться и лишнее не мешает):

            rpm_sum += (micros() - micros_prev);

            Я бы при делении просто проверил делитель на == 0 и если да, то установил некое максимальное значение RPM_MAX.


            1. jaiprakash
              20.06.2015 21:11

              rpm_sum += micros() - micros_prev;
              


            1. jaiprakash
              22.06.2015 11:46

              Хотя, если подумать, в данном случае

              micros() - micros_prev == 0
              означает дребезг, и нужно просто выходить из обработчика.


  1. nomadmoon
    20.06.2015 11:36
    +4

    А если вдруг ошибка в управлении то винт расколбасит в щепки или ничего страшного не случится?


    1. RasselFast
      20.06.2015 17:28

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


  1. ringman
    20.06.2015 12:41
    +1

    А что произойдет если МК сгорит, зависнет?
    Шаг винта останется на последней величине или уйдет в какое-то положение?


    1. RasselFast
      20.06.2015 17:18

      Если сгорит МК, то шаг винта останется в том положении, в каком он был до этого. А если зависнет, то через 2 секунды он просто перезапустится, и продолжит работать дальше.


  1. gleb_l
    20.06.2015 23:03
    +2

    что понравилось в решении — то, что фактический режим мотора перекладки шага определяется датчиком тока — это самый надежный способ, как раз уровня аэрокосмической промышленности ;)
    Чего не хватает — это диагностики исправности компонентов системы, используя этот датчик — например, отсутствие детектируемого тока после выдачи команды, слишком большой время перекладки, превышение максимального тока двигателя итд — все эти ситуации хорошо бы ловить алгоритмически и обрабатывать, например защищая обмотку двигателя при заклинивании редуктора ВИШ или несработке концевика (это чревато пожаром)
    Еще я не увидел в алгоритме регулирования ни интегральной (вернее она есть длительностью в один цикл), ни дифференциальрой составляющих (она константная-10 rpm) — в итоге, алгоритму может не хватать демпфирования, и он даже в стационарном режиме может давать непрерывные колебания вокруг оптимальной точки, изнашивая мотор и редуктор управлеия ВИШ


  1. AIV_Electronics
    19.06.2015 19:07
    +5

    А в чём суть статьи? В чём научная новизна и практическая значимость? Какие проблемы автор героически преодолевал решая поставленную задачу? Очень уж не подробно обо всём написано.
    Найдётся крайне немного народа, кому нужен управляемый шаг винта. Уж очень тематика узкая и механика важнее электроники.


    1. gleb_l
      20.06.2015 22:30

      Это же не докторская диссертация, а рассказ об инженерном решении одной частной задачи — он не обязан быть ни научно-новым, ни широкоприменимым. Вполне себе хорошая статья имхо — заслуживает +1. Другой вопрос — сядете ли вы в arduino-controlled aircraft? Я лично крепко подумаю ;). Правда, если данная конкретная модель самолета способна взлететь в положении самого тяжелого винта с максимальным взлетным весом — то теоретически ардуино испортить ничего не сможет — так как продолжать полет или садиться самолет сможет и подавно на любом шаге


      1. Korogodin
        21.06.2015 12:08

        У меня arduino-controlled aircraft вызовет меньше подозрений, чем любая другая не сертифицированная самоделка. Ардуина проста, отработана, протестирована миллионами, а это только способствует увеличению надежности.


        1. gleb_l
          22.06.2015 14:32

          Имхо, ардуино в системе управления самолетом нужно сравнивать не с самоделкой, а со штатной системой. Иначе в случае сбоя и/или аварии это будет слабым отмазом — «комиссия признает, что крушение произошло по причине сбоя несертифицированного электронного модуля, но в утешение родственников можем со всей авторитетностью заявить, что любой другой несертифицированный DIY-модуль явился бы причиной крушения гораздо раньше. Приносим свои соболезнования»


  1. Ocelot
    19.06.2015 22:04
    +1

    Вот этот кусок вызывает вопросы:

    rpm_sum = rpm_sum + (60000000.0 / (micros() - micros_prev));

    1) Если дернуть прерывание RPM_IN() быстро два раза подряд, вывалится деление на ноль?
    2) Что происходит при переполнении micros()? А это случается каждые 70 минут.


    1. RasselFast Автор
      20.06.2015 02:22

      1) Нет.
      2) Условимся, что прерывание срабатывает каждые 10,000 микросекунд.
      Предположим что после переполнения:
      micros() == 5,000
      micros_prev==4,294,962,296
      Далее идет операция (micros() — micros_prev), в числах это будет: 5,000 — 4,294,962,296
      В рамках типа переменной unsigned long результат вычисления будет равен 10,000.

      Переполнение никак не повлияло на результат.


      1. jaiprakash
        20.06.2015 10:59
        +2

        И всё же нужно переписать строку с возможностью деления на 0. Это же авионика, а не мигание светодиодом на столе, тут всё должно быть по MISRA C, даже двух команд на строке нельзя:

        micros_prev = micros(); rpm_val++;

        Из кода я так и не понял откуда взялось micros(), приведён фрагмент программы?

        Хоть статья понравилась, выглядит странным использование ардуино (как софта) в таком ответственном изделии. Программа на чистом С почти ничем не будет отличаться от приведённого скетча, за исключением полного контроля за происходящим. А так — остаётся элемент магии.


        1. NikitaKA
          20.06.2015 12:22

          откуда взялось micros()

          Это вшитая функция, есть еще millis(), например.


        1. RasselFast Автор
          20.06.2015 17:10

          Подкорректировал функцию обработки прерывания. Теперь работать будет быстрее, и на 0 делить возможности не будет.

          // Функция обработки сигнала с тахометра с усреднением данных
          void RPM_IN() {
            rpm_sum = rpm_sum + (micros() - micros_prev);
            micros_prev = micros(); 
            rpm_val++;
            if (rpm_val >= 10) {
              rpm = 600000000 / rpm_sum;
              rpm_sum = 0;
              rpm_val = 0;
            }
          }
          

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


          1. jaiprakash
            20.06.2015 17:48

            Может arduino не поддерживает, но в С обычно пишут так (труднее ошибиться и лишнее не мешает):

            rpm_sum += (micros() - micros_prev);

            Я бы при делении просто проверил делитель на == 0 и если да, то установил некое максимальное значение RPM_MAX.


            1. jaiprakash
              20.06.2015 21:11

              rpm_sum += micros() - micros_prev;
              


            1. jaiprakash
              22.06.2015 11:46

              Хотя, если подумать, в данном случае

              micros() - micros_prev == 0
              означает дребезг, и нужно просто выходить из обработчика.


              1. RasselFast Автор
                22.06.2015 20:48

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


                1. Ocelot
                  22.06.2015 22:31

                  Это может быть импульсная помеха, окисленный контакт, да мало ли что.


                  1. RasselFast Автор
                    23.06.2015 18:04

                    Добавил проверку на дребезг.

                    // Функция обработки сигнала с тахометра с усреднением данных
                    void RPM_IN() {
                      if (micros() - micros_prev <= 4) {
                        rpm_error++; // +1 к счетчику ошибок тахометра 
                      }
                      else {
                        rpm_sum += (micros() - micros_prev);
                        micros_prev = micros();
                        rpm_val++;
                        if (rpm_val >= 10) {
                          rpm = 600000000 / rpm_sum;
                          rpm_sum = 0;
                          rpm_val = 0;
                        }
                      }
                    }

                    Добавить переменную.
                    int rpm_error = 0; // Счетчик ошибок тахометра

                    Заменить основной цикл.
                    void loop() {
                      wdt_reset(); // Сбрасывам счетчик wdt
                      if (rpm_error > 10) {
                        HAND; // Принудительно ручной режим, если ошибок тахометра больше 10
                      } else {
                        MODE();
                      }
                      CURR();
                      LED();
                    }


  1. nomadmoon
    20.06.2015 11:36
    +4

    А если вдруг ошибка в управлении то винт расколбасит в щепки или ничего страшного не случится?


    1. RasselFast Автор
      20.06.2015 17:28

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


  1. ringman
    20.06.2015 12:41
    +1

    А что произойдет если МК сгорит, зависнет?
    Шаг винта останется на последней величине или уйдет в какое-то положение?


    1. RasselFast Автор
      20.06.2015 17:18

      Если сгорит МК, то шаг винта останется в том положении, в каком он был до этого. А если зависнет, то через 2 секунды он просто перезапустится, и продолжит работать дальше.


  1. gleb_l
    20.06.2015 23:03
    +2

    что понравилось в решении — то, что фактический режим мотора перекладки шага определяется датчиком тока — это самый надежный способ, как раз уровня аэрокосмической промышленности ;)
    Чего не хватает — это диагностики исправности компонентов системы, используя этот датчик — например, отсутствие детектируемого тока после выдачи команды, слишком большой время перекладки, превышение максимального тока двигателя итд — все эти ситуации хорошо бы ловить алгоритмически и обрабатывать, например защищая обмотку двигателя при заклинивании редуктора ВИШ или несработке концевика (это чревато пожаром)
    Еще я не увидел в алгоритме регулирования ни интегральной (вернее она есть длительностью в один цикл), ни дифференциальрой составляющих (она константная-10 rpm) — в итоге, алгоритму может не хватать демпфирования, и он даже в стационарном режиме может давать непрерывные колебания вокруг оптимальной точки, изнашивая мотор и редуктор управлеия ВИШ


  1. RasselFast Автор
    22.06.2015 20:32

    Еще я не увидел в алгоритме регулирования ни интегральной (вернее она есть длительностью в один цикл), ни дифференциальрой составляющих (она константная-10 rpm) — в итоге, алгоритму может не хватать демпфирования, и он даже в стационарном режиме может давать непрерывные колебания вокруг оптимальной точки, изнашивая мотор и редуктор управлеия ВИШ
    Процесс регулирования сильно упрощается тем фактом, что нет необходимости балансировать вокруг оптимальной точки, достаточно лишь попасть в диапазон (дельта от -60 до 60). Нет принципиальной разницы, сколько будет 4000 rpm или 4050 rpm. Попав в диапазон, алгоритм выдает команду STOP. Обмотка эл. двигателя накоротко замыкается через нижние плечи полумостов, что вызывает почти мгновенную остановку.
    Чего не хватает — это диагностики исправности компонентов системы, используя этот датчик — например, отсутствие детектируемого тока после выдачи команды, слишком большой время перекладки, превышение максимального тока двигателя итд — все эти ситуации хорошо бы ловить алгоритмически и обрабатывать, например защищая обмотку двигателя при заклинивании редуктора ВИШ или несработке концевика (это чревато пожаром)
    Еще не хватает из важного:
    1. Полноценного ручного режима управления. Даже профессиональные решения не застрахованы от выхода из строя электроники. Для этого применяется прямая коммутация электродвигателя механическим переключателем. Переведя еще один переключатель из автоматического режима, в ручной, электроника полностью отсекается от управления эл. приводом.
    2. Возможности менять настройки прибора без необходимости вносить изменения в прошивку. Нужно простое приложение для ПК с простым интерфейсом, либо доп. устройство (как вариант).


    1. gleb_l
      24.06.2015 00:21

      Электрически коммутировать режим «автомат-ручной» можно реле с двумя парами переключающих контактов. Обмотку реле при этом нужно запитать через конденсатор и выпрямитель с одного из выводов порта ВВ, усиленного, например, транзисторным каскадом. Чтобы включить и удерживать автоматический режим работы, МК система должна будет непрерывно генерировать меандр на этом выводе. Если это делать программно (скажем, в основном цикле), а не аппаратным таймером, то любое зависание основного цикла приведет к отпусканию реле и автоматическому отключению мотора ВИШ от МК системы и подключению его к «железным» кнопкам