Например TDA7294

РадиоКот > Схемы > Цифровые устройства > Игрушки

Простой контроллер лодочного мотора

Автор: Jotto
Опубликовано 15.08.2014.
Создано при помощи КотоРед.

Начну издалека. Как-то пару лет назад мой приятель и коллега по работе купил себе и детям игрушку (точно не знаю кому больше, себе или детям) - радиоуправляемый катер. Катер был вполне китайский, простой и, на удивление, живучий. Плавал вполне шустро и рулился весьма сносно. В общем - веселая игрушка. Не смотря на то что катер насквозь китайский (даже с гордыми наклейками типа "Гоночный Катер Из Китая"), собран он был по вполне взрослой модельной схеме - простой но стандартный двухканальный передатчик на 40МГц, отдельный приемник, отдельный контроллер скорости (также именуемый регулятором хода) с регулятором напряжения для электроники, стандартная модельная серва на руль, ну и двигатель - относительно неплохой коллекторник. Однако китайцы всеж китайцы, контроллер двигателя никак не защищен от воды, а так как в катер так или иначе попадает немного воды, то плата контроллера со временем покрывалась окислами и вообще выглядела все хуже и хуже. Но стойко продолжала работать.

Потом приятель захотел небольшого апгрейда, взял имевшийся у него цифровой передатчик на 2.4ГГц (от самолета), прикупил дополнительный приемник, подключил вместо штатного, взял трехбаночный литий-полимер вместо штатного металл-гидрида на 7.2В, но.... со слов "я там когда аккумулятор подключал что-то куда-то не так, проскочила искра и все, контроллеру кердык..." В общем, отдал он его мне на посмотреть и, может, починить...

При ближайшем рассмотрении выяснилось что это несложный аналоговый контроллер на паре компараторов в одном корпусе SO8 (LM323), куча мизерной (0603 или типа того) рассыпухи, регулятор на LM1117-5 и источник опорного напряжения, ну и силовой ключ на мосфете. Дальнейшее исследоване показало что контроллер вообще не был расчитан на напряжение выше 10 вольт - входная емкость была на 10 вольт. Помер чип с компараторами и защитный диод (мосфет IRL3803 остался живой). Возиться с этим окислившимся китайским аналогом не очень хотелось, тем более что в наличии не было такого-же корпуса с LM323, зато вспомнил что в загашнике лежит кучка микроконтроллеров (Счаз все как скажут - Ооо! Опять на микроконтроллере!) ATtiny13 в таком-же корпусе SO8. Кроме того я по профессии программист, мне проще написать немного кода чем привести в чувство аналоговую схему чуть сложнее эмиттерного повторителя :-). Посему было решено убрать с платы все ненужное, и впаять на место компараторов микроконтроллер.

На самом деле получилось гораздо проще чем было. Я сдул феном с платы практически все детали кроме фильтрующих керамических конденсаторов, 5-ти вольтового LDO регуляторя и силового "логического" мосфета. Заменил электролитический конденсатор на 100мкФ 25В и защитный диод. Припаял тиньку и два резистора, один на входе от приемника (небольшая защита входа), второй от ноги тиньки до затора мосфета (ограничитель тока перезаряда затвора - защита выходного каскада в микроконтроллере), перерезал пару-тройку мешавших дорожек, кинул пару-тройку перемычек там где надо. Вот и все! Можно еще добавить резистор 10КОм от ножки Res на +5 вольт, для предотвращения самопроизвольного сброса, но это уже из разряда паранои. В общем - смотрите схему. На этом с электронно-железной частью можно покончить, она предельно проста. Только один момент, для фильтрации помех со щеток мотора нужно припаять с каждого контакта мотора на его корпус по керамическому конденсатору примерно 0.1 мкФ, и точку соединения корпуса и конденсаторов припаять на общий (минусовой) провод контроллера, это на схеме не показано, так как находится прямо на моторе.

 

Кстати, фото того что вышло - не будет, отладив контроллер я густо залил это дело термоклеем для герметизации, так что кроме белого комка с торчащими проводами и хвостом силового транзистора смотреть не на что.

Остальное колдовство это, собственно, программа для контроллера. Так как для ATtiny я писать еще не пробовал, то это был неплохой полигон для экспериментов. Итак, у нас есть целый килобайт программной памяти а функций, подлежащих реализации, совсем не много, посему можно писать на Си. Впрочем, ассемблер я и не знаю толком, так что все равно - Си. В частности это AVRStudio 4.19 + AVR-GCC.

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

Начнем с конца. Т.е. с выходного ШИМ. На тине13 есть один 8-битный таймер и два 8-ми битных аппаратных ШИМ канала, нужно только правильно настроить регистры и больше ни о чем не беспокоится. Вполне себе достаточно и даже с лихвой. Определимся с частотой. Встроенный тактовый генератор выбран 9.6МГц, делитель тактовой выключен, делитель на таймер - 8, итого частота тиканья таймера 1.2МГц, таймер и регистр сравнения 8-ми битный, значит период ШИМ примерно 4.7КГц - что вполне подходит для небольшого коллекторного дигателя.

Дальше нужно прочитать входные импульсы и померить их длину, точнее, длительность. Сигнал управления одного пропорционального канала в модельной аппаратуре выглядит как импульс шириной от 1 миллисекунды (крайне-левое/нижнее положение рычага управления) до 2 миллисекунд (крайне-правое/верхнее) с периодом примерно 20 миллисекунд. Центральное положение ручки, соответственно, 1.5 миллисекунды. Впрочем, эта информация легко ищется на необъятных просторах сети. Все это довольно примерно, так как зависит от производителя радиоаппаратуры и настроек. Мой экземпляр радиоаппаратуры при нулевых настройках триммеров давал интервал длины импульса от 1.02 до 1.97 миллисекунды на канале газа. В нашем контроллере есть прерывание на изменение состояния произвольно выбранной ножки, таким образом, настроив нужным образом регистры, мы получим прерывание при наступлении фронта и спада входного импульса, что именно - фронт или спад - можно узнать, прочитав состояние этой ножки. Механизма антидребезга вводить не нужно, это не кнопка а вполне чистый сигнал. Конечно, некоторую защиту от ложных импульсов и помех мы предусмотрим, но пока будем считать что входной сигнал дребезга не содержит.

Собственно, теперь встает вопрос, как посчитать длину таких импульсов с приемлемой точностью. Вспомним, у нас есть 8-ми битный таймер, тикающий с частотой 1.2МГц, период тика 0.8(3) микросекунды, период переполнения 0.8(3)*256 = 213 микросекунд (0.213 миллисекунды). Возьмем с запасом 2.5 миллисекунды на входной импульс даст 3000 тиков таймера, что на порядок больше его разрядности, то же время если сделать программный таймер и считать время в прерывании таймера на переполнении то получим 11 отсчетов, так как нам интересны интервалы от 1 до 2 мс, то получим всего 4-5 отсчетов на рабочий интервал - такое разрешение слишком мало для пропорционального управления. Можно пойти на компромисс - сделать счетчик времени комбинированным, старший байт будет увеличиваться программно в прерывании на переполнении таймера, а младший байт использовать из аппаратного счетчика таймера. Таким образом мы получим 16-ти битные отсчеты с периодом в 0.8 мс, что нам очень хорошо подходит. Входные импульсы будут иметь диапазон от 1200 до 2400 при рабочем диапазоне в 1200 тиков. Если чуть-чуть сузить края рабочего диапазона то получим 1024 отсчета, что очень удобно для масштабирования в двоичном коде простым сдвигом. Т.е. поделив на 4 при помощи сдвига на 2 бита вправо можно записать это значение в регистр ШИМ и, таким образом, регулировать напряжение на моторе. В прерывании на изменении входной ножки на фронте импульса запомним значение 16-ти битного таймера, а на спаде вычтем текущий таймер из запомненного, получив время импульса в тиках таймера, выставим флажок, который расскажет главному циклу что есть новое значение для обработки. Всю остальную работу по проверкам, перерасчетам, масштабированиям и перенастройкам ШИМ-регистров мы будем делать в главном цикле, не заботясь особенно о быстродействии и объеме кода. В принципе на этом можно было-бы и закончить если бы не пара нюансов. Как говорится, дьявол кроется в деталях.

Во-первых, если в прерывании по фронту/спаду читать и объединять два байта, программный и аппаратный, то мы с большой долей вероятности получим ошибку. Дело в том что таймер считает независимо от хода программы, поэтому, прочитав аппаратный и программный таймер мы не можем быть уверены в том что эти два значения согласованы. Например мы сначала прочитали аппаратный таймер и получили значение 0 (он только что перекинулся с 255 на 0), и затем прочитали программный таймер, скажем, 2. Верная эта двойка? Скорее всего нет, потому что мы уже находимся в процедуре обработки прерывания по изменению состояния ножки, поэтому аппаратный таймер выставил флаг на исполнение прерывания по переполнению (для увеличения программного таймера) но это прерывание еще не исполнилось, поэтому, на самом деле была-бы не двойка а тройка, а поскольку мы ошиблись на единицу в старшем байте счетчика, то ошибка составит 256, т.е. 25% диапазона - это слишком много. Если сначала читать программный счетчик а потом аппаратный то ничего не изменится, мы можем получать несогласованные значения обоих счетчиков. Так что же делать? Как я уже говорил, при наступлении состояния прерывания микроконтроллер выставляет флаг в одном из служебных регистров, которые мы в состоянии прочитать, таким образом, в нашем рабочем прерывании можно узнать, нет ли отложенного прерывания по переполнению таймера, и скорректировать старший байт на единичку. Тут следует отметить что обработчики прерываний должны отрабатывать как можно быстрее, например, этот обработчик в целом займет 40-50 тактов процессора, а если обработчик распухнет, да еще таймер будет тикать на частоте осциллятора а не деленной на 8, то мы можем пропустить уже два и более прерываний на переполнение, а это уже недопустимо совершенно. Вернемся к нашим тикам. Итак, мы прочитали аппаратный таймер, потом считали программный, затем проверили флажок отложенного прерывания и обнаружили что он взведен, прибавили единичку к программному таймеру... опа, опять ошибка! а почему? А потому что мы могли прочитать аппаратный таймер ДО переполнения, помните, программа сама по себе а таймер сам по себе, тут он как раз взял и переполнился и мы считали флаг переполнения уже взведенный. Снова рассогласованные значения. Тут уже проще, если мы считали флаг переполнения то просто перечитаем аппаратный счетчик снова, он уже точно перевалил через границу счета, а ошибка в пару-тройку тиков аппаратного таймера будет далее не существенна, мы все равно поделим время на 4 и два младших разряда таймера уйдут в небытие. На самом деле мы поделим на 8, дискретность в 128 ступенек вполне достаточна, но об этом позже.

Во-вторых, мы не будем передавать данные о ширине импульса напрямую на ШИМ генератор, для управления нам интереснее завести некую передаточную функцию, что-бы зависимость напряжения на моторе была нелинейной от угла поворота ручки. Вообще говоря, она будет логарифмической, об этом тоже можно почитать в интернетах, например, тут. Поэтому заведем табличку преобразования и будем подавать наше значение на вход как индекс таблички и брать значения для ШИМ генератора из ячейки таблички. Кроме того, таблицу составим таким образом, что-бы иметь в начале небольшой запас значений 0 а в конце 255 - сузив еще немного диапазон, на всякий случай, чтоб точно попасть в значения, передаваемые с передатчика. Кроме того, как я говорил, можно еще и сузить диапазон входных значений до 0..127, для нас это не критично, а память можно сэкономить. Таблицу я составил в экселе и просто скопировал в код как константу, расположенную в программной памяти. Как ни странно, можно было оставить и 256 значений, памяти хватало, но если вы захотите добавить плюшек и фишек, то лишние 128 байт будут совсем не лишние. В принципе, кроме табличного преобразования (и, очевидно, прямого математического расчета) есть методика под названием кусочно-линейной аппроксимации, но в данном случае мы можем воспользоваться просто таблицей.

В третьих есть нюанс с работой ШИМ-а. Если записать в регистр значение 0 то это не выключит ШИМ а будет выдавать один имульс таймера, таким образом диапазон регулирования ШИМ от 0.4 до 100%, то есть при включении и отключении моторчика кроме перезаписи регистра скважности нужно переконфигурировать регистр управления выходом.

В четвертых введем небольшую защиту от ложных импульсов, скажем, не будем реагировать на импульсы короче 600 тиков (0.5 мс) и длиннее 3000 (2.5мс), импульсы меньше 1288 будем считать за 1288 (начало рабочего диапазона) а импульсы длиннее 2312  считать за 2312 (конец диапазона). Таким образом, рабочий диапазон будет от 1288 до 2312 (1.08 мс..1.93 мс)

Ну и в пятых, я добавил простую защиту - блокировку запуска двигателя при включении питания, т.е. пока газ не сбросить до нуля то двигатель не будет реагировать на входные импульсы. Иначе, забыв убрать ручку газа до нуля, рискуем получить по рукам винтом при включении питания.

Все исходники прилагаются, даже сносно комментированы (правда, на ломаном английском, рабочая привычка) так что любой желающий может все посмотреть, исправить найденные ошибки и добавить своих. Кроме того осталось еще 3 (а с ножкой сброса целых 4) рабочие ножки, компаратор и аналогово-цифровой преобразователь плюс более половины программной памяти, так что есть еще где развернуться.

P.S. Кстати, вот еще интересная и объемная статья про контроллеры модельных моторов.


Файлы:
исходники и прошивка


Все вопросы в Форум.


ID: 1943

Как вам эта статья?

 Нравится
 Так себе
 Не нравится

Заработало ли это устройство у вас?

 Заработало сразу
 Заработало после плясок с бубном
 Не заработало совсем

8 6 3