Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Мастерство управления двигателем постоянного тока: экспертные советы и трюки

Компоненты и материалы

Компонент Количество Примечание
Arduino Due 1 Можно использовать любую плату Arduino.
Makeblock Me TFT LCD 1 Опционально. Можно использовать другой дисплей или обойтись без него.
Резистор 4.75 кОм 4 Значения резисторов могут варьироваться в зависимости от реализации.
Потенциометр (generic) 4 3 из них опциональны (для настройки коэффициентов регулятора).
Полупроводниковый прибор PNP (generic) 4 Транзисторы могут варьироваться в зависимости от реализации.
Двигатель постоянного тока (generic) 1
Тумблер (Slide Switch) 1 Используется для выбора направления.
Фотоэлектрический датчик скорости HC-020K 1
Плата для макетирования (generic) 1
Перемычки (generic) 1

Приложения и онлайн-сервисы

О проекте

Управление скоростью и направлением двигателей постоянного тока с помощью ПИД-регулятора и ШИМ-выходов

Введение

Почти во всех доступных проектах авторы хотят управлять скоростью и направлением двигателей, но чаще всего предпочитают подавать ШИМ-сигнал напрямую на двигатель, даже через схему управления двигателем. Но такой метод всегда терпит неудачу, если вам нужно точно поддерживать заданную скорость из-за «близнецов» под названием «трение» и «инерция».

(Никогда не вините Близнецов. Что бы вы ни хотели сделать, с чем-то или без чего-то, Близнецы тут же появляются и действуют, чтобы помочь вам держать всё под контролем. Инерция заставляет вещи «думать» перед действием, а трение ограничивает их ускорение и скорость. И «мощность» — это «ничего», если она не под полным контролем.)

Если вы пытаетесь управлять скоростью двигателя, подавая входной сигнал как ШИМ на выход, фактическая скорость никогда не достигнет заданной точки, и будет существенная разница (ошибка), как видно на изображении выше. Здесь нам нужен другой способ — «ПИД-управление».

ПИД-регулятор

Что такое ПИД-управление? Представьте, как вы водите машину: Чтобы начать движение с полной остановки, нужно нажать на педаль газа сильнее, чем при обычной езде. Во время движения с (почти) постоянной скоростью вам не нужно сильно давить на газ, вы просто компенсируете потерю скорости при необходимости. Кроме того, вы слегка отпускаете педаль, если ускорение выше нужного. Это также способ «экономичной езды».

ПИД-регулятор делает именно то же самое: он считывает разницу «Сигнал ошибки (e)» между заданной точкой и фактическим выходом. У него есть 3 компонента: «Пропорциональный», «Интегральный» и «Дифференциальный»; название регулятора образовано от первых букв каждого. Пропорциональная компонента определяет наклон (ускорение) выходного сигнала регулятора относительно сигнала ошибки. Интегральная часть суммирует сигналы ошибки во времени, чтобы минимизировать конечную ошибку. Дифференциальная компонента следит за ускорением сигнала ошибки и вносит «корректировку». Подробнее можно найти в интернете.

В моей программе для Arduino ПИД-регулятор написан как функция:

float controllerPID(float _E, float _Eprev, float _dT, float _Kp, float _Ki, float _Kd) {
  float P, I, D;
  /* Базовая формула: U = _Kp * ( _E + 0.5*(1/_Ki)*(_E+_Eprev)*_dT + _Kd*(_E-_Eprev)/_dT ); */
  P = _Kp * _E; /* Пропорциональная компонента */
  I = _Kp * 0.5 * _Ki * (_E+_Eprev) * _dT; /* Интегральная компонента */
  D = _Kp * _Kd * (_E-_Eprev) / _dT; /* Дифференциальная компонента */
  return (P+I+D);
}

Тогда итоговое выходное значение определяется простым сложением текущего выходного значения и выхода ПИД-регулятора. Следующий фрагмент основной программы вместе с расчетом сигнала ошибки и выхода ПИД-регулятора:

/* Сигнал ошибки, выход ПИД-регулятора и итоговый выход (ШИМ) на двигатель */
E = RPMset - RPM;
float cPID = controllerPID(E, Eprev, dT, Kp, Ki, Kd);
if ( RPMset == 0 ) OutputRPM = 0;
else OutputRPM = OutputRPM + cPID;
if ( OutputRPM < _minRPM ) OutputRPM = _minRPM;

Схема питания двигателя постоянного тока

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

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

После этого я решил использовать четыре биполярных транзистора BC307A PNP в схеме «мост» для определения направления тока через обмотки двигателя (на самом деле набор NPN BC337 работал бы лучше из-за способности выдерживать значительно большие коллекторные токи, но у меня их не было в тот момент).

Поскольку токи двигателя должны проходить через эмиттер-коллекторный переход транзистора, необходимо использовать транзисторы с примерно одинаковыми коэффициентами усиления по току (hfe). Для проверки можно использовать следующую схему и отобрать транзисторы, дающие примерно одинаковые показания амперметра. При проектировании таких предварительных схем нужно учитывать:

Теперь можно определить значение резистора, подключаемого к базе: Сначала нужно учесть ограничения выхода вашей платы управления и стараться держать базовый ток минимально возможным (поэтому рекомендуется выбирать транзисторы с максимально возможным коэффициентом усиления по току). Возьмите номинальное напряжение выхода на плате управления как «Триггерное напряжение» (VT), и найдите Требуемый базовый ток (IBreq), разделив Ток двигателя (IM) на Коэффициент усиления по току (hfe) транзистора: IBreq = IM / hfe.

Затем определите Напряжение, падающее на Резисторе (VR), вычитая Напряжение включения база-эмиттер (VBEon) из Триггерного напряжения: VR = VT - VBEon.

Наконец, разделите Напряжение на Резисторе (VR) на Требуемый базовый ток (IBreq), чтобы найти Значение Резистора (R): R = VR / IBreq.

[ Комбинированная формула: R = ( VT - VBEon ) * hfe / IM ]

В моем случае:

Реверс направления и важные примечания

Чтобы изменить направление вращения двигателя постоянного тока, достаточно изменить направление тока. Для этого можно просто сделать мостовую схему с четырьмя наборами транзисторов. По схеме: ШИМ-выход #2 активирует T1A и T1B, а ШИМ-выход #3 активирует T2A и T2B, так ток, проходящий через двигатель, меняется.

Но здесь нужно учесть еще одну проблему: При пуске электродвигатели потребляют пусковой ток, значительно превышающий номинальный ток, который вы измеряете во время нормальной/непрерывной работы (производители указывают только номинальные токи). Пусковой ток может составлять примерно 130% от номинального для маломощных двигателей и увеличиваться в зависимости от мощности двигателя. Если вы запитаете двигатель напрямую от источника напряжения и сразу же измените полярность во время работы, двигатель будет потреблять экстремальные уровни тока, так как он не полностью остановился. В конечном итоге это может привести к сгоранию источника питания или обмоток двигателя. Это может быть не так важно для очень маломощных двигателей, но становится важным, если увеличиваются уровни мощности. Но если вы запитываете двигатель через транзистор или набор транзисторов (как Дарлингтон), такой проблемы нет, так как транзисторы уже ограничивают ток.

В любом случае, я предусмотрел небольшую процедуру в программе: При смене направления во время работы программа сначала обнуляет оба командных выхода и ждет полной остановки двигателя. Затем завершает свою задачу и возвращает управление основной процедуре.

if ( Direction != prevDirection ) {
  /* Обнуляем оба ШИМ-выхода на двигатель */
  analogWrite(_chMotorCmdCCW,0);
  analogWrite(_chMotorCmdCW,0);
  /* Ждем, пока скорость двигателя упадет */
  do {
    RPM = 60*(float)readFrequency(_chSpeedRead,4)/_DiscSlots;
  } while ( RPM > _minRPM );
}

Считывание скорости

В моем приложении я использовал дешевый датчик скорости HC-020K. Он выдает импульсы на уровне своего напряжения питания, и даташит говорит, что напряжение питания 5В. Однако моя плата — Arduino Due, и она не может принять 5В. Поэтому я запитал его напрямую от 3.3В выхода Due, и да, это сработало. Следующая функция написана для чтения частоты и выхода HC-020K.

int readFrequency(int _DI_FrequencyCounter_Pin, float _ReadingSpeed) {
  pinMode(_DI_FrequencyCounter_Pin,INPUT);
  byte _DigitalRead, _DigitalRead_Previous = 0;
  unsigned long _Time = 0, _Time_Init;
  float _Frequency = 0;
  if ( (_ReadingSpeed<=0) || (_ReadingSpeed>10) ) return (-1);
  else {
    _Time_Init = micros();
    do {
      _DigitalRead = digitalRead(_DI_FrequencyCounter_Pin);
      if ( (_DigitalRead_Previous==1) && (_DigitalRead==0) ) _Frequency++;
      _DigitalRead_Previous = _DigitalRead;
      _Time = micros();
    } while ( _Time < (_Time_Init + (1000000/_ReadingSpeed)) );
  }
  return (_ReadingSpeed * _Frequency);
}

Обратите внимание, что колесо HC-020K имеет 20 щелей, просто считанную частоту нужно разделить на 20, чтобы получить обороты в секунду как частоту. Затем результат умножить на 60, чтобы получить об/мин.

RPM = 60 * (float)readFrequency(_chSpeedRead,4) / _DiscSlots;

Графические дополнения

Для отображения входных данных и результатов я использовал Makeblock Me TFT LCD и написал функцию CommandToTFT() для отправки команд на него. На самом деле причина этой функции — просто изменить точку последовательного подключения в одной строке программы, когда это необходимо.

Функции Cartesian_Setup(), Cartesian_ClearPlotAreas() и Cartesian_Line() написаны для подготовки графической области, очистки области построения при достижении конца горизонтальной оси (здесь это «время») и построения графиков соответственно. Обратитесь к руководству Makeblock Me TFT LCD для получения подробностей, если вас интересуют графические функции, потому что я не буду объяснять их здесь, так как они выходят за рамки этой статьи.

Заключение

Здесь я привожу программу с графическими функциями и без них отдельно, чтобы вы могли рассмотреть реализацию управления скоростью и направлением автономно или с графикой. Кроме того, в кодах вы найдете дополнительные объяснения для запрограммированных функций.

Наконец, обычно нельзя снизить скорость двигателя постоянного тока ниже 10-20% от его номинальной скорости, даже без нагрузки. Однако с помощью ПИД-управления для не нагруженного двигателя постоянного тока после его запуска можно снизить скорость почти до 5%.

Редакция (25.02.2018): Если вы хотите использовать NPN-транзисторы вместо PNP, нужно также учитывать обратный ток для обоих типов. При открытии (включении) ток течет от Эмиттера к Коллектору в PNP-транзисторах, но для NPN типов это наоборот (от Коллектора к Эмиттеру). Следовательно, PNP-транзисторы поляризованы как E(+) C(-), а для NPN должно быть C(+) E(-).

Код

Код с графическими дополнениями (Arduino)

/* ############################################### Константы цветов для Makeblock Me TFT LCD ############################################### */
#define _BLACK 0
#define _RED 1
#define _GREEN 2
#define _BLUE 3
#define _YELLOW 4
#define _CYAN 5
#define _PINK 6
#define _WHITE 7
/* ############################################### Назначение I/O ############################################### */
int _chSpeedSet = A0, // Уставка скорости
    _chKp = A1, // Чтение пропорционального коэффициента для ПИД
    _chKi = A2, // Чтение интегрального коэффициента для ПИД
    _chKd = A3, // Чтение дифференциального коэффициента для ПИД
    _chMotorCmdCCW = 3, // ШИМ-выход на двигатель для против часовой стрелки
    _chMotorCmdCW = 2, // ШИМ-выход на двигатель для по часовой стрелке
    _chSpeedRead = 24, // Чтение скорости
    _chDirection = 25; // Чтение селектора направления
/* ############################################### Другие константы ############################################### */
#define _minRPM 0 // Минимальные об/мин для начала смены направления
#define _maxRPM 6000 // Предел максимальных об/мин
#define _Tmax 90 // Максимальный лимит времени для графиков
#define _DiscSlots 20 // Количество щелей на индексном диске
/* ############################################### Глобальные переменные ############################################### */
String Cartesian_SetupDetails;
boolean Direction, prevDirection; // Настройки тревог
float RALL=500.0, RAL=1000.0, RAH=4000.0, RAHH=4500.0;
float Seconds=0.0, prevSeconds=0.0, prevRPM=0.0, prevRPMset=0.0, RPM=0.0, RPMset=0.0, OutputRPM=0.0, Kp=0.0, Ki=0.0, Kd=0.0, Kpmax=2.0, Kimax=1.0, Kdmax=1.0, E=0.0, Eprev=0.0, dT=1.0;
/* ############################################### CommandToTFT(TFTCmd) Функция команды для Makeblock Me TFT LCD ... */
void CommandToTFT(String TFTCmd) {
  Serial1.println(TFTCmd);
  delay(5);
}
/* ... (остальной код опущен для краткости, полный код доступен во вложениях) ... */

Код без графических дополнений (Arduino)

/* ############################################### Назначение I/O ############################################### */
int _chSpeedSet = A0, _chKp = A1, _chKi = A2, _chKd = A3,
    _chMotorCmdCCW = 3, _chMotorCmdCW = 2,
    _chSpeedRead = 24, _chDirection = 25;
/* ############################################### Другие константы ############################################### */
#define _minRPM 0
#define _maxRPM 6000
#define _DiscSlots 20
/* ############################################### Глобальные переменные ############################################### */
boolean Direction, prevDirection;
float RPM=0.0, RPMset=0.0, OutputRPM=0.0, Kp=0.0, Ki=0.0, Kd=0.0, Kpmax=2.0, Kimax=1.0, Kdmax=1.0, E=0.0, Eprev=0.0, dT=1.0;
/* ... (функции readFrequency, controllerPID, setup, loop аналогичны выше, но без графических функций) ... */

Схемы

Это прототип для объяснения управления скоростью двигателя постоянного тока с использованием ПИД-регулятора и того, что нужно учитывать при реверсе.

Производственный процесс

  1. Повышение производительности двигателей постоянного тока с сплавами вольфрам-медь
  2. Создание аудио-эффектов, управляемых датчиками, с набором Satellite CCRMA
  3. Управление двумя шаговыми двигателями через джойстик на Arduino Nano — простой урок (Visuino)
  4. Мастерство 8×8 LED-матрицы с Arduino Uno: Пошаговое руководство
  5. Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
  6. Библиотека 8-битного порта ввода-вывода для Arduino — расширение цифрового управления
  7. Arduino 64-клавишная прототипная клавиатура: матрица на сдвиговых регистрах
  8. TFT Shield 2.8" 320×240 SPI для Arduino Nano — высокопроизводительный дисплей
  9. Гальванически разделённый аналоговый вход для Arduino на LM331 и оптопаре 4N25
  10. Набор для создания робота с умной внутренней навигацией на базе Arduino