Проект «Качок»

Поступил от одной фирмы заказ. Нужно было разработать мозги для электрической помпы, которую они проектировали. Предназначалась эта штука для проверки датчиков давления в полевых условиях. Собственно, помпа уже была. Ручная. Но, оказалось, что, для того, чтобы накачать 40 атмосфер вручную, нужно быть качком. Качки среди тетенек-метрологов — редкость. Следовательно, ручной труд нужно было срочно механизировать!

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

А вот с электронной начинкой что-то пошло не так. Инженеры заказчика сначала попытались сделать все сами. Конечно же на ардуино. Прицепили к ней силовую часть на реле, кнопки, токовый датчик… И, получили что-то очень грустное, и упорно не желающее работать как надо. Но общий принцип и бета версия прототипа у меня была. Осталось все воплотить на более достойном уровне.

По идее, схему сначала как-то прототипируют, пишут софт, а уже потом разводят плату. Но, можно сделать наоборот. В данном случае, схемотехника была примерно понятна. Есть готовый драйвер коллекторного двигателя. Есть контроллер, функционал которого, в любом случае, задается софтом. А это позволяет подключать его ноги практически произвольно. Есть цепи питания и всякой периферии. Проще, сразу развести всё на плате, чем делать двойную работу, собирая на проводках похабную макетку.

Плату буду делать в EagleCAD.

Платка была мелкая, в ограничение демоверсии влезала легко. Первым делом, решил нарисовать цепь питания. Контроллер потребляет мало. Значит, хватит обычного линейного стабилизатора. Делаем ему обвязку из конденсаторов на входе и выходе. Не забываем зашунтировать электролиты керамикой, а то у них огромная индуктивность, и наносекундные импульсы они почти не фильтруют.Так… А чем включать? Актуатор жрёт довольно неслабый ток. А заказчик дал нам гламурную кнопочку, чтоб было красиво. Что делать? Будем усиливать. В разрыв цепи ставится Р-канальный мосфет, который открывается кнопкой. Современные транзисторы могут схавать дикие токи при очень мелких габаритах. Заодно, получаем халявную защиту от переполюсовки.

Чтобы совсем не запутаться, разводим часть платы. Переходим в трассировщик, и ужасаемся. Первое ощущение — ступор и паника. На экране девственно пустая плата. В углу, кучкой, навалены детали, а между ними ктулхическое переплетение соединений. Спутанные наушики видели? А теперь, представьте, что их полный рюкзак.

Растаскиваю компоненты по плате, и начинаю рисовать дорожки. Вроде получается. Часть схемы постепенно обретает вменяемый вид. Переношу на плату стабилизатор. Рисую. Смотрю на результат. Нецензурно ругаюсь. Удаляю часть дорожек и переделываю. Кажется, внутренний перфекционист удовлетворен. Можно идти дальше.

Перехожу обратно к схеме. Впихиваю контроллер. И сразу разъем для программирования. Надо, чтобы чип прошивался прямо на плате. Шить их перед запайкой было бы ни разу не технологично. Рисуем разъемы под кнопки и светодиод индикации. Добавляем делитель напряжения, чтобы измерять, что у нас там по питанию. И, обязательно, гнусную пищалку!

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

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

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

Разумеется, модуля в библиотеке EagleCAD нет. Придется рисовать.

Задаем условное обозначение на схеме. Перерисовываем плату, стараясь не ошибиться с габаритами. Игл радует тем ,что координаты начал и концов можно прям цифрами вносить в свойства линий. И не надо ничего подгадывать и считать клеточки. Затем вбиваем соответствие ног на схеме и на плате. Готово!

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

Еще несколько штрихов. Разглядываю плату. Правлю мелкие косяки. Кажись, можно воплощать в железе.

жЫрно печатаю маску с дорожками на бумаге. Через неё мы будем засвечивать фоторезист!

Если посмотреть бумагу на просвет, видно, что тонер закрашивает её недостаточно плотно. Это плохо. Скорее всего, через такую маску засветится что не надо, и будет брак. На этот случай есть специальная жижа, которая вызывает набухание тонера и его уплотнение. Зовется она Density Toner и купить ее можно в фирмах продающи расходники для типографий. Рублей 400 за баллон стоит, хватает очень надолго. Еще можно шаблон подержать в парах ацетона, от них тонер тоже набухает знатно.

Фоторезист выглядит как тонкая пленка. Её накатывают на плату, засвечивают через маску, и смывают. Там, где на неё воздействовал ультрафиолет, она стабилизируется и так просто уже не смывается. В результате, у нас получается рисунок дорожек.

Важно накатать пленку ровно, без пузырей и заломов. Лучше всего с этим справляется ламинатор.

Фоторезист засвечен и смыт проявителем. Остается протравить плату в хлорном железе.

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

Шел второй час кодинга. Устремив взор в белое безмолвие монитора я пытался разобраться с регистрами незнакомого мне ранее контроллера. В какой-то момент мне захотелось бросить всё, и написать программу на Ардуино… Я обернулся. Ди Хальт смотрел на меня, и с укоризной во взгляде правил лезвие своего кукри, как бы намекая, что не стоит его разочаровывать.

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

У контроллера нет никакой многозадачности. По кругу выполняется одна единственная программа, в которой и происходит всё интересное. Чтобы многозадачности, все таки, добиться, есть особые приемы. В первую очередь, прерывания.

Прерывания — это особые события, на которые контроллер отвлекается и быстро выполняет куски кода, возвращаясь потом к основной программе. Допустим, прилетел байт в UART. Надо скопировать его в какой-нибудь буфер. Ждать нельзя, а то прилетит следующий, вытолкает из регистра тот, что был, и мы его потеряем. А вот если вынести код, пихающий байты в буфер, в прерывание, то в момент прихода байта контроллер будет его быстренько сохранять, почти не тормозя выполнение основной программы.

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

Это как посадить семечко, и через каждые несколько секунд его откапывать и смотреть, насколько оно подросло.

Пока программа прокручивала цикл с задержками, контроллер безответственно профукивал бросок тока. Уменьшить задержки? Тоже плохо.

Вообще, ардуино не запрещает делать все на прерываниях. Проблем тут две.

Первая — обычно, те, кто учится прогать на ардуино, не копают глубоко. Они просто не знают, что вообще бывают прерывания, регистры, и все такое. Бабуино — это такой особый путь.

Ну и вторая — библиотеки ардуино делают без ведома программиста кучу неведомой хрени, стараясь упростить ему жизнь. В результате, попытки напрямую обратиться к аппаратным ресурсам могут привести к неожиданным глюкам и непонятному времени исполнения. А нам, напомню, надо все делать очень быстро.

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

По току на движке можно понять, что происходит. Чем сильнее нагружаешь двигатель, тем больше он жрет. Заклинило, уперся в стенку — ток будет максимальным. Значит, ориентируясь по току, легко можно сделать автоматику как у дверей лифта, которые, если что-то не дает закрыться, отходят обратно.

АЦП контроллера тикает с определенной частотой. Как только он померял, что на него приходит, он выдает прерывание. Вот в это прерывание я и засунул кусок кода, отвечающий за измерение тока. Туда же засунул измерение напряжения питания. Сварганив простенький конечный автомат. Пригодится.

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

Теперь нужно было разобраться с кнопками. У нас целых три таймера. Их можно заставить выполнять что-то в прерывании, в то время, как основной цикл занят своими делами.

Заказчик хотел две сенсорные кнопки. Одна должна включать привод, пока на нее давишь. Вторая включать и выключать.

С первой все совсем просто. Кнопка нажата — есть флаг разрешения работать. Основной цикл врубает движок. Нет — вырубает.

Со второй все чуть сложнее. Простейшее решение, сделать так, чтобы нажатие кнопки инвертировало какой-то флаг. Тычешь один раз — он сменяется с «выкл» на «вкл». Еще раз — наоборот.

Работать это будет. Но, криво. С ложными срабатываниями. Чтобы всё было идеально четко, нужно реализовать конечный автомат. В общем, логику как у авторучки с кнопкой. Нажимаешь один раз, алгоритм поднимает флаг, и переключается в следующее состояние, в котором ждет отпускания кнопки. Нажимаешь второй — флаг сбрасывается, и программа снова ждет отпускания. При этом, нажатие кнопки срабатывает четко, и её не трясет как от болезни Паркинсона.

Кстати, о тряске. У механических кнопок контакт замыкается не сразу. Какие-то миллисекунды он дребезжит. Контроллер быстрый, и успевает принять это за кучу нажатий подряд. На этот случай можно ввести итератор, который будет переключать конечный автомат с следующее состояние только если несколько циклов подряд состояние кнопки не будет меняться. Примерно так:

-У нас кнопка нажата?
-Да, нажата.
-Точно нажата?
-Да!
-А точно нажата?
-ДА, ЕПТА!!!
-А точно-точно нажата?
-ААААААААААААААААААААААА!!!!!!!!!!1111

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

Программа уже почти готова. Основной цикл получился не сложный. Но, оброс процессами, вынесенными в прерывания. По сути, это уже многозадачность.

Загружаем код в контроллер. Подаем питание. РАБОТАЕТ!!!

В том, как полученный агрегат совершал возвратно-поступательные движения, определенно, чувствовалось что-то фрейдистское.

Внести флюгегехаймен!!

Настало время допиливания. Первым делом надо было как то нагрузить актуатор, чтобы понять насколько адекватно у нас идет измерение тока. Ведь от тока зависел и момент. Ага, легко сказать. У него усилие в несколько сот килограмм. И я, даже навалившиьсь на него всем весом, не смог бы создать сколь-нибудь ощутимой нагрузки. Ди посмотрел на это, схватил нож и куда то убежал. Вернулся через пять минут с обрезком толстого резиного шланга, сантиметров на 10. Я даже думать не хочу у кого он его отрезал. Натянули шланг на шток актуатора, на манер крайней плоти. Осталось только воткнуть отвертку в отверстие на конце штока, чтобы шлангу не куда было деваться и попробовать его сжать. Сопротивление кусок резины оказал достойное, удалось даже заклинить актуатор, выведя его на максимальную нагрузку.

Нагрузка есть, первым делом, я решил откалибровать датчик тока. Ноги UARTа очень удачно оказались на разъеме, к которому должен цепляться светодиод. Ничто не мешало врубить его режиме отладки, и подключиться к компу.

Оказалось, что сигнал довольно зашумлен. График слегка колбасило.

Чтобы это побороть, я сделал кольцевой буфер. Контроллер при каждом измерении тока записывает результат в массив, пока не наберется 32 значения. Когда нам нужно узнать ток, мы перемножаем их все, и вычисляем среднее арифметическое. Получился простенький аналог RC цепочки.

Шумы исчезли, осталась только плавная линия, рисующая график того, как мы нагрузили двигло.

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

Допилил еще кучу мелочей. Результат мне уже нравился. В какой-то момент, стало ясно, что он соответствует техзаданию, а в чем-то его даже превосходит.

Настало время суровых испытаний.

В торжественной тишине мы внесли устройство в лабу к заказчику. Под барабанную дробь подключили помпу, которой оно должно было рулить. И…

Оно заработало.

И тут выяснилось, что есть одна проблема. Помпа работает как с воздухом, так и с жидкостью. Воздух сжимается. Качать его нужно долго. Жидкость же накачивается до нужного давления буквально мгновенно.

Так вот. Движок давит со всей дури. И пока сработает защита по току (у нас же кольцевой буфер с интеграцией, и заполняется он не сразу), он успевает накачать слишком много.

Уменьшить буфер? Система начинает реагировать на пусковой ток, как на превышение нагрузки.

Начался мозговой штурм. Как бы это бысто поправить прям тут, не переписывая всю программу полностью.

Предложили сделать так, чтобы после срабатывания концевика программа плавно повышала ток на двигателе, а буфер уменьшить. Потом, предложили сделать физический токовый стабилизатор, который бы не давал движку развивать усилие больше заданного. Благо токовые стабилизаторы валялись буквально под ногами.

Мне представилась пирамида из костылей. Ага. Нужно построить зиккурат.

И тут…

Это похоже на луч света, внезапно озаривший пасмурное небо. Инсайт! Я дописал одну… Всего одну строчку кода! И двигатель стал плавно разгоняться ШИМом, и развивать строго определенное усилие.

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

Просто, в прерывание АЦП я добавил строку, которая, если ток становился больше определенного, отключала его до следующей итерации. И этого оказалось достаточно. АЦП тикает с довольно высокой частотой. Значит, он, совершенно естественным образом будет обрезать большой пусковой ток, автоматически создавая ШИМ с нужной скважностью. А индуктивность двигателя его сгладит. Если же движок упрется в препятствие, его усилие, так же, будет ограниченно заданным током.

А что с реверсом по превышению тока? А он никуда не делся. Пока ШИМ ограничивает пиковый ток, кольцевой буфер заполняется его значениями. И, как только, среднее арифметическое станет больше заданной величины, сработает реверс.

Решение оказалось настолько простым и изящным, что я не мог поверить. А что, так можно было?!

Оказалось, да.

Устройство уехало на выставку.

Функциональный прототип готов. Впереди допиливание, ресурсные испытания, ловля оставшихся багов, и, если повезет, предсерийный образец.

 

Проект «Качок»: 2 комментария

  1. На сленге электриков — не «конечник», а «концевик» — «концевой выключатель», или КВ сокращенно.
    По коду: основной цикл должен выполняться быстро, опрос кнопок, КВ и обработку данных с АЦП тоже можно делать в основном цикле. Антидребезг делается за несколько опросов (по одному разу в одном цикле). Все нужные задержки отрабатываются ‘флагами’ и количеством (главных) циклов, delay можно поставить один, в конце главного цикла.
    С «псевдоШИМ» — интерсная идея!
    Слог хорош, пишите ещё)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *