Продолжение разработки ПИД-регулятора скорости вращения двигателя постоянного тока. В уроке запустим двигатель без обратной связи. Научимся измерять временные параметры импульсов дискретного сигнала.
Предыдущий урок Список уроков Следующий урок
Попробуем управлять двигателем только с помощью ШИМ, не используя датчик оборотов.
Регулировка скорости вращения двигателя без обратной связи.
Я написал простую программу, которая формирует ШИМ пропорциональный напряжению на входе A0.
Она:
- Измеряет напряжение сигнала на входе A0.
- Усредняет его для защиты от помех.
- Формирует ШИМ с коэффициентом заполнения пропорциональным среднему напряжению на выводе A0.
- При формировании ШИМ учитывает “мертвое время”.
- Выводит значение ШИМ в последовательный порт для контроля.
Вот скетч программы:
Поясню, что такое “мертвое время”. Допустим, ШИМ работает с высокой частотой, например, 62,5 кГц. Если мы зададим ему коэффициент заполнения 1, то это означает, что с периодом 16 мкс будет формироваться импульс длительностью 0,0625 мкс. Импульс такой короткой длительности транзисторный ключ не отработает, не успеет. В результате транзистор будет какое-то время в полуоткрытом режиме и не к чему хорошему это не приведет. Особенно на высоком напряжении.
Поэтому необходимо искусственно ограничивать импульсы минимальной длины. Если значение 1 транзистор не способен отработать, значит, вместо него необходимо формировать 0. Тоже самое в конце диапазона ШИМ. Например, значение 254 необходимо заменить на 255.
Отработку ”мертвого времени" производит следующий блок программы.
#define DEAD_TIME 10 // мертвое время
// мертвое время
if( valPwm < DEAD_TIME ) valPwm=0;
if( valPwm > (MAX_PWM - DEAD_TIME) ) valPwm= MAX_PWM;
Если значение ШИМ меньше заданного, оно заменяется на 0. Если больше, то оно равно максимальному значению ШИМ.
В программе в определенных пределах можно изменять частоту периода ШИМ.
TCCR2B= 1; // 62 500 Гц
//TCCR2B= 2; // 7 812 Гц
// TCCR2B= 3; // 1 953 Гц
// TCCR2B= 4; // 977 Гц
// TCCR2B= 5; // 488 Гц
// TCCR2B= 6; // 244 Гц
// TCCR2B= 7; // 61 Гц
Для формирования ШИМ используется таймер 2 и вывод 11.
Можно переключиться на вывод 3. Изменения коснутся только строки.
TCCR2A= 0b00100011;
Использование других выводов недопустимо.
Загружаем скетч в контроллер, открываем монитор последовательного порта.
Вращаю переменный резистор, подключенный к входу A0. Монитор показывает изменение ШИМ. В положении резистора от 0 до максимума ШИМ равен 0, затем скачком меняется до 10. Дальше плавное изменение до 245 и скачок до 255. Т.е. заданное ”мертвое время” 10 отрабатывается правильно.
Дальше подключаем к схеме питание 12 В и проверяем работу ключа с мотором-вентилятором. Я проверил для разных частот ШИМ. Как не странно, лучше всего работает на низких частотах 244 и 61 Гц. Мотор начинает вращаться с ШИМ равным 30. На частоте 62,5 кГц вентилятор начинает вращаться при значении ШИМ 60. На средних частотах он еще противно пищит.
Когда Игорь проводил эти испытания на мощном двигателе 500 Вт, он категорично выбрал высокую частоту 62,5 кГц. На высоких частотах его двигатель вращается равномерно, без вибраций. Тише работает, начинает крутиться с меньшего значения ШИМ. Т.е. для каждого двигателя лучше выбирать частоту ШИМ экспериментально.
В любом случае регулировка с помощью ШИМ без обратной связи работает, скорость двигателя изменяется плавно. Конечно, частота оборотов непредсказуема и зависит от механической нагрузки.
Измерение периода и частоты входных импульсов с помощью Ардуино.
Чтобы стабилизировать скорость вращения мотора необходимо ее измерять. А скорость в свою очередь определяется частотой импульсов датчика Холла. Об этом сказано в предыдущем уроке. Как следствие возникает задача – измерение периода и частоты импульсов. Давайте на короткое время забудем про двигатель и научимся измерять частоту импульсов дискретного сигнала.
Задача не очень простая. Скорость вращения мотора у Игоря достигает 12000 об/мин. При такой скорости и использовании с датчиком Холла двух магнитов надо измерять временные параметры с периодом 2,5 мс. Если мы хотим обеспечить точность не более 1%, то разрешающая способность измерителя должна быть не более 250 мкс.
Но бывают и более скоростные двигатели. Часто используются датчики, которые формируют более 2 импульсов на оборот. Это еще уменьшает время дискретности измерителя.
А с другой стороны двигатель может вращаться и со скоростью 60 об/мин. Это соответствует периоду импульсов 0,5 сек.
Вывод:
- наш измеритель должен иметь высокую разрешающую способность по времени (не более десятков мкс)
- и широкий диапазон измерения (не менее 1 сек).
Измерять период с точностью десятков микросекунд чисто программными средствами невозможно. Даже если мы подадим измеряемый сигнал на вход внешнего прерывания, вряд ли это позволит решить задачу. Обработка прерывания может задерживаться другими прерываниями, например, счетчиком системного времени. А это будет искажать время измерения.
Поэтому будем использовать аппаратный узел микроконтроллера – таймер в режиме захвата. У микроконтроллера ATmega328 только таймер 1 может работать в этом режиме.
Лучше будет, если вы почитаете об этом режиме в документации на ATmega328. Я расскажу коротко и чисто с практической точки зрения.
Входной сигнал подключаем к входу ICP1 (вывод 8). Использование других выводов недопустимо.
Микроконтроллер выделяет нужный фронт сигнала на входе ICP1 (я задал перепад с высокого уровня на низкий) и по нему перегружает содержимое таймера 1 в специальный регистр ICR1. Можно считать значение этого регистра и тем самым узнать, когда был перепад входного сигнала, даже если чтение произошло позже самого события.
Дальше немного сложно в понимании, но объем информации небольшой. При желании можно разобраться по шагам.
Мы задаем режим работы таймера 1. Переводим его в режим простого счетчика от внутреннего генератора с максимальной частотой. В этом режиме каждые 0,0625 мкс к счетчику прибавляется 1. При достижении максимального значения 65536, он начинает считать с 0. Также задаем режимы для захвата и разрешаем прерывания таймера 1 по захвату и переполнению.
// установка режима захвата таймера 1
pinMode (8, INPUT_PULLUP); // вход сигнала захвата ICP, входные измеряемые импульсы
TCCR1A = 0; // нормальный режим работы таймера 1
TCCR1B = 0; // выбор отрицательного фронта входного сигнала
TCCR1B = (1 << ICNC1) | (1 << CS10); // включение подавления шума входного сигнала, частота тактирования - внутренний генератор, без деления
TCNT1 = 0; // сброс счетчика
TIMSK1 = (1 << ICIE1) | (1 << TOIE1); // разрешения прерываний таймера 1 по захвату и переполнению
Создаем обработчик прерывания по захвату (фронту входного сигнала).
// прерывание по сигналу захват (по отрицательному фронту измеряемого сигнала)
ISR (TIMER1_CAPT_vect) {
periodTime = (unsigned long)ICR1 | (((unsigned long)numOverflowTimer1) << 16);
TCNT1 -= ICR1;
numOverflowTimer1 = 0;
}
В нем мы считываем значение регистра ICR1 и сохраняем его в переменной periodTime.
Дальше нам надо сбросить счетчик таймера в 0, чтобы отсчет следующего времени начался с 0. Но с момента, когда реально был захват, прошло неизвестное нам время. Надо было его сбрасывать в 0 в момент захвата. Но тогда мы, возможно, отрабатывали другое прерывание. Поэтому мы вычитаем из счетчика значение его в момент захвата.
TCNT1 -= ICR1;
Что равносильно сбросу в 0 в момент захвата.
В результате вышеописанных действий в переменной periodTime оказывается время между захватами. Т.е. время между отрицательными фронтами входного сигнала. Реальное время будет равно значению periodTime, умноженному на дискретность таймера 0,0625 мкс.
Все было бы хорошо, но при периоде сигнала более 4096 мкс ( 65536 * 0,0625 мкс) таймер 1 переполнится. Значит, нам надо считать еще и переполнения таймера 1.
Для этого создаем обработчик прерываний по переполнению таймера.
// прерывание по переполнению таймера 1
ISR (TIMER1_OVF_vect) {
numOverflowTimer1++;
}
И полученное значение прибавляем к periodTime.
periodTime = (unsigned long)ICR1 | (((unsigned long)numOverflowTimer1) << 16);
Теперь все. В переменной periodTime получаем период входных импульсов. Для вычисления реального времени необходимо умножить его на 0,0625 мкс.
Пишем программу измерения временных параметров входного сигнала и проверяем ее работу.
Для проверки формируем на выводе 5 сигнал ШИМ с частотой 976,56 Гц.
analogWrite(5, 200); // формирование тестовых импульсов на выводе 5 (976,56 Гц)
Соединяем вывод 8 с выводом 5. Запускаем монитор последовательного порта.
Тестовый сигнал формируется аппаратным способом, поэтому имеет высокую стабильность.
Надо проверить работу нашего измерителя в полном диапазоне.
Для этого тестовый сигнал на выводе 5 формируем с помощью системного времени Ардуино.
Период задается в строке.
#define TEST_TIME 10 // время периода тестового сигнала (мс)
Проверяем для периода 10 мс.
Вот период 100 мс
Период 1 сек.
Высокой точности от формирования тестового сигнала с помощью системного времени ждать не приходится. Но измеритель работает нормально в широком диапазоне периода входного сигнала.
Такой способ измерения частоты и периода сигналов может использоваться в других приложениях.
В следующем уроке вернемся к двигателю. Будем измерять его скорость вращения.
Предыдущий урок Список уроков Следующий урок
Может я рановато, тема только началась. Если что удалите коммент.
Для не очень точной регулировки частоты (>5%) пользуются обратной связью по напряжению. Частота вращения прямо пропорциональна напряжению на роторе (не знаю, среднему или среднеквадратичному). Если учесть падение на активном сопротивлении ротора, то можно еще точности добавить.
Обычно в ключ ставят защиту по току, на КЗ и на длительную перегрузку, ну и чтоб делать поправку на падение напряжения на сопротивлении ротора.
На картинках частота указана в Hg, хотя обычно это Hz (герц).
Здравствуйте!
Частота вращения, конечно, пропорциональна напряжению двигателя, но эта зависимость нелинейна и зависит еще от механической нагрузки. Проще использовать датчик.
Наверное, добавить защиты в окончательном варианте устройства вполне здравая мысль.
Насчет обозначения единицы измерения частоты Гц вы правы. Как-то это упустил.
Для (коллекторного?) электродвигателя зависимость скорости вращения от напряжения, а момента от тока линейная, это законы физики. Другое дело, что если ток ротора мы можем просто померить, напряжение от которого зависит частота вращения величина теоретическая, за вычетом всех потерь. В основном это падение на активном сопротивлении ротора.
(Напряжение ротора)=(напряжение на входе) — (ток двигателя)*(сопротивление ротора).
Там есть еще разные потери в магнитном сердечнике и на индуктивностях рассеяния, но в штатном режиме они незначительны.
На коллекторных двигателях ставят еще дроссели и конденсаторы для уменьшения помех. На больших частотах ШИМ будут повышенные потери в желЕзе, больше килогерца имеет смысл ставить фильтр или дроссель как в контроллере элемента Пельтье.
Датчик использовать получится не всегда, на высокооборотных двигателях потребуется балансировка и нагрузки серьезные из-за центробежной силы.
Мой опыт работы ограничивается управлением индукторными, шаговыми двигателями. Немного работал с асинхронными. Двигателями постоянного тока я управлял только на эмпирическом уровне. Примерно, как сейчас.
Так что спорить с вами не могу. Но не представляю, как вычислять обороты двигателя по напряжению при разных механических нагрузках. Будет время — попробую почитать теорию.
Контроль тока двигателя в станках особенно важен потому что инструмент может заклинить или при неправильно выбранном режиме обработки будет постоянная перегрузка, что ведет к перегреву двигателя и регулятора. Кстати, датчик температуры на корпусе двигателя тоже весьма желателен.
Термин «мёртвое время» относится больше к двухтактным каскадам, когда для исключения сквозного тока сначала выключают включенный транзистор, а после некоторой задержки включают выключенный.
Для однотактных уместней максимальное и минимальное время.
Извините за дотошность, но этот сайт мне нравится серьезным подходом к материалу, если считаю что есть неточность, стараюсь на нее указать.
Здравствуйте! Не соглашусь.
Вы говорите о мертвом времени для исключения сквозных токов. То, про что я пишу, тоже мертвое время, только для исключения слишком коротких импульсов.
Не соглашайтесь, но «мертвое время это время, в течение которого выключены оба силовых элемента для предотвращения сквозного тока через них». Второго управляемого силового элемента на схеме не указано. Поэтому точнее — ограничение минимальной длительности включенного или выключенного состояния транзистора. Deadtime control в вашей схеме нет.
Доброго времени!
Спросите у вашего друга. с какого минимального напряжения начинает работать двигатель в 500 Вт на его сверлильном станке.
И зачем нам тратить разряды шим регулятора когда двигатель еще не работает. Вот еще одна мертвая зона
Здравствуйте!
Ответил, что начинает стабильно вращаться с 5-7 В. Но у него двигатель на 100 В.
Хороший двигатель, При номинале в 100 В начало работы с 5%? И еще, в силовой электронике используют ШИМ до 8кГц — дальше сильно растут потери (железо греется и начинает проявляться скин-эффект. Отсоветуйте 61 кГц. И на дорогих транзисторах/диодах сэкономит, ибо при 61кГц ШИМ нужно ставить транзисторы и диоды с полным временем переключения много меньше 1/100 периода ШИМ, скажем раз в 20 (для уменьшения потерь), что сразу приводит к необходимости зарядить/разрядить затвор транзистора (то есть нужен драйвер) для предотвращения линейного режима, пускай кратковременного,- либо сильно гробить разрешающую способность ШИМа. Да и диоды на низких частотах вполне обычные (с соответствующей рабочей частотой) работают и не Шоттки (нужен радиатор). Для примера — у всех импульсных БП с частотой от 15 кГц выходной транзистор управляется одноплечевым (TL494) или полумостовым драйвером. Ну и там же можно посмотреть все силовые элементы, включая диоды.
Спасибо за разработку, применил для своей сверлилки плат. Мотор 48В, 200Вт, ток хх 0.7А,12000 об/мин. настройки Кp=0,01, Ki=0.01, Kd=0. Kd ухудшает работу. Прикрутил двухстрочный экран по i2c. Вывел на него pwm в %, обороты заданные и обороты со счетчика, ну и старт/стоп. В планах прикрутить либо кнопки либо энкодер для настройки оборотов и включения выключения. Еще хочу добавить в код плавный запуск, так как импульсный блок питания мотора 200Вт уходит в защиту при запуске при выставленных оборотах более 8 тыс.
62.5 кГц много для ключа, а 7,8 кГц и ниже пищит, поэтому можно еще сделать на втором таймере для 11 выхода 31,4 кГц, выставляем биты таймера TCCR2B = 0b00000001; TCCR2A = 0b00000001; и радуемся тишине ну и ключу IRF650 с драйвером на трех транзисторах полегче в два раза, он без радиатора чуть теплый…
В качестве датчика оборотов не плохо справляется ардуиновский датчик препятствий. Плюс нет магнитов и дисбаланса. Приклеил на переходник патрона фольгу в качестве отражателя. Единственный минус ловит помеху от ШИМ. Помеху практически не заметно на 7,8 кГц, а на 31.4 и 62.5 мешает здорово, после 6 тыс об/мин число выборок усреднения практически не помогает, проскакивает в мониторе порта через 6…12 нормальных значений, двойное вычисленное значение порядка 12 тыс об, соответственно шим отрабатывает в минус ( видно на осциллографе). Думаю в этом случае надо вводить другую обработку типа циклически замкнутого кругового массива с игнорированием ложных показаний, но это машинное время. У себя решил аппаратно, между датчиком препятствия и мк поставил, фильтр помех на двух элементах триггера Шмитта, между которыми интегрирующая RC цепь, 3кОм и 0.1мкФ.
Здравствуйте! Почему число выборок усреднения АЦП максимум 64?
Здравствуйте!
Скорее всего, я отвел под переменную усреднения значений АЦП 16 разрядов (uint16_t). Значение АЦП 10 разрядов. Остается 6 разрядов или 64 значений. Если изменить тип переменной усреднения, то число выборок можно увеличить.
Добрый день!
Очень заинтересовался данным проектом. Спасибо вам за его создание и пояснения к нему, и вообще за уроки. Все доходчиво и грамотно изложено.
К сожалению не могу получить доступ к скетчам, т.к. не могу провести оплату. Подскажите пожалуйста порядок действий…
Так же есть вопрос:в тексте по предыдущему уроку не понимаю куда идут линии связи с пина для включения двигателя и с пина тестового сигнала (для чего он нужен не ясно).