Управляем сервоприводами из OpenWRT без Arduino

  • Tutorial

Краткий пост о том как можно избежать лишних элементов в системе с сервоприводами и использовать железо по максимуму


Предыстория


Я весьма давно и плотно болен Linux, OpenWRT, сетевыми и беспроводными технологиями, безопасностью, а теперь еще и стал потихоньку заражаться роботостроением и умными домами. Все это очень круто, особенно когда есть столько готовых шаблонов, свободного и открытого исходного кода, а временами можно совсем перейти на сторону зла и быстренько накидать логику в Scratch.
Но потом просыпается интерес уже не просто поморгать светодиодами, вау-эффект проходит и необходимо решать прикладные задачи. Вроде и тут следовало бы восхититься обилием готового, но дьявол как всегда в деталях. Одно дело — управлять логикой ЕСТЬ/НЕТ, это позволяет легко включать или отключать свет, можно даже датчик качества воздуха (MQ-135) подцепить и включать вытяжку при необходимости. Все это круто, но на дворе 21 век, космические корабли бороздят большой театр и душа просит чего-то по-круче. Взор мой пал на управление сервоприводами. Почему бы и нет? Тема весьма широкая, ведь они присутствуют во многих механизмах, от роботов до простых открывалок-закрывалок. Плюсом так же является и то что в летательных аппаратах двигатели управляются аналогично и это расширяет диапазон использования просто в разы.

Заинтересовавшихся приглашаю под кат

Те кто уже давно знаком с темой и хочет перейти сразу к сути — смело проматывайте до раздела "Пошаговая инструкция".


Начнем с начала


Чтобы суть этой заметки была понятна всем, стоит сперва обратить внимание на составляющие сервопривода.

image

Электродвигатель, редуктор, потенциометр и контроллер. Все гениальное просто, не правда ли?

Для управления сервоприводом используется широтно-импульсная модуляция или ШИМ. Ничего сложного, это просто сигнал в виде импульсов прямоугольной формы. основными параметрами является ширина импульса и ширина «паузы». «Пауза», а лучше называть ее правильно — период, задает частоту сигнала. Скажем, если у нас ширина периода равна 100 мс, то частота будет равна 10 Гц. Посчитать очень просто: переводим миллисекунды в секунды и делим единицу на это число. Соответственно, 100мс = 0,1с и если 1 разделить на 0,1 то получим 10. Можете проверить на калькуляторе.

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



А на осциллографе вот так:



Теперь поговорим о том как сервопривод воспринимает такой сигнал. И уже тихонько подкрадывается дьявол с деталями.
Дело в том что контроллер может быть цифровой или аналоговый.
Если совсем по-простому, то разница в том что аналоговый контроллер подает или не подает напряжение только в момент импульса. Выставив интервал импульса 40, 120 или, скажем, 240 мс можно заметить как сервопривод начнет «дергаться» при работе. Все потому что внутри стоит микросхема и частота работы всего сервопривода равна частоте внешнего сигнала. Стандартные 20 мс это 50 Гц, 40 мс это 25 Гц, и по аналогии. Соответственно, 50 или 25 раз в секунду на двигатель подается (или не подается) напряжение. Снизив частоту можно существенно уменьшить крутящий момент и добиться более медленной работы механизма, правда ценой уже описанного «дергания».
Цифровые контроллеры, как правило, представляют из себя небольшой микропроцессор с обвязкой. Ключевое отличие от аналоговой микросхемы в том что внутренняя частота работы постоянна. Вы можете сколько угодно снижать частоту управляющего сигнала, это будет влиять только на время реакции, но крутящий момент будет постоянным. Хотя, выдавая изменение положения через длинные промежутки и небольшими порциями, можно добиться медленной скорости вращения. Тут уже зависит от конкретного сервопривода и его параметров.

Как генерировать сигнал?


Для этого обычно применяют какой-нибудь микроконтроллер, особенную любовь питают к платформе Arduino. Там все просто. Используется готовая библиотека, скармливаем нужной функции параметры сигнала и получаем на заданном GPIO нужной ширины импульсы.
Но что делать если нет возможности использовать микроконтроллер, сопряженный с основным устройством, а мощности самого контроллера для решения задач, ну, никак не хватает? Остается искать альтернативные варианты. И таких есть у меня!
Как уже стало понятным из заголовка, будет использоваться операционная система OpenWrt. Которая по сути своей является полноценным дистрибутивом на ядре Linux. А это дает широкие возможности и гибкость настройки. OpenWrt и ее производные активно используются в различных системах «умный дом», но об этом в другой статье. Как же генерировать ШИМ (или на буржуйском PWM) сигнал? Оказывается, не многим сложнее чем на Arduino. Для этого необходимо задействовать все те же GPIO, а вместо библиотеки модуль ядра под названием PWM-GPIO-Custom. Последняя стабильная версия OpenWrt где он работает — 12.09, но чтобы это понять я потратил около недели, пытаясь заставить работать на текущем Trunk. Не знаю по какой причине, но в официальном репозитории пакета с этим модулем нет и придется собирать его самостоятельно, но это не так сложно. Ниже я напишу как.

Пошаговая инструкция


Итак, для начала нам необходимо загрузить сборочный инструментарий OpenWrt. Хотя, если совсем честно, то начать нужно с уcтановки Linux, но я надеюсь что многие из вас этот пункт уже выполнили.
Итак, вы создали папку для инструментария, перешли в нее
Выполнить загрузку исходников можно командой
git clone git://git.openwrt.org/12.09/openwrt.git
У вас же присутствует терминал в нижней части окна, правда?
Жаль, это очень удобно.

После загрузки нужно перейти в папку openwrt и скачать пакеты командой
git clone git://git.openwrt.org/12.09/packages.git

Теперь у нас есть все исходные коды пакетов. Хотя постойте… А как же pwm-gpio-custom? Его нет.
Не отчаивайтесь, вот он
Нужно просто распаковать содержимое в openwrt/package и все будет хорошо.

Теперь перейдем непосредственно к сборке.
Находясь в папке openwrt необходимо выполнить make -j n kernel_menuconfig
Вместо n нужно подставить число ваших ядер + 1.
Откроется синее меню. Выбираем пункт Device Drivers.



Находим PWM Support:


Активируем пункт PWM emulation using GPIO. Выбирать пробелом. Нужно чтобы везде стояли звездочки, это важно:



После этого нужно немного переконфигурировать ядро. Ищем соответствующий пункт:



Ставим звездочку на пункте High Resolution Timer Support, выставляем значение Timer frequency на 1000HZ, а в параметре Premption Model выбираем Low-Latency Desktop:



Необходимо наверняка знать аппаратную платформу своего роутера. Но еще важнее указать ее в конфигурации. У меня это Atheros ar71xx:




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

Теперь нужно таким же способом сконфигурировать сборку самой ОС командой make -j n menuconfig

Затем в меню Kernel Modules:



Выбрать Other modules:



И поставить звездочку на пункте kmod-pwm-gpio-custom:



Все, можно приступить к сборке. Все та же команда make -j n

Остается откинуться на спинку кресла и что-нибудь посмотреть, можно попить чаю/кофе, процесс сборки не быстрый.
Как только сборка закончится, можно переходить в папку bin. В ней будет папка с вашей платформой и образы. Прошиться можно в полном соответствии со стандартной инструкцией. Как только завершится процесс прошивки, можно смело заходить через telnet. Необходимо будет еще дополнительно закачать пакет kmod-pwm-gpio-custom на само устройство. Это можно сделать через SCP, либо через wget, или же установить openssh-sftp-server и воспользоваться FileZilla.

Загружать сам пакет лучше в директорию /tmp, так как ПЗУ не резиновая, а данная директория физически располагается в оперативной памяти, которой обычно от 32 до 64 Mb. После закачки пакет необходимо установить командой opkg install /tmp/kmod-pwm-gpio-custom_xxx.ipk. Можно сильно не заморачиваться с названием пакета, автодополнение по TAB прекрасно работает.

Генерация ШИМ сигнала


После установки пакета можно переходить к непосредственному управлению GPIO и генерации ШИМ сигнала.
Для этого необходимо активировать модуль ядра. Сделать это можно командой insmod pwm-gpio-custom bus0=0,23 bus1=1,20
Это просто пример того как оно может быть. busX задает номер шины, которой можно управлять через символьное устройство под этим самым номером в /sys/сlass/pwm У нас их появится два: gpio_pwm.0:0 и gpio_pwm.1:0. Манипулировать параметрами ШИМ можно просто записывая соответствующие переменные в файлы. Да, чуть не забыл, все значения задаются в наносекундах. Поехали:

echo 10000000 > /sys/class/pwm/gpio_pwm.0\:0/period_ns Задает период. В данном случае это 100 Гц.
echo 8500000 > /sys/class/pwm/gpio_pwm.0\:0/duty_ns Задает скважность.
Да, некоторые выводы инвертированы по умолчанию и необходимо задать время «пустоты» внутри периода. Если же значением High для GPIO явдяется 1, то нужно задать echo 1500000 > /sys/class/pwm/gpio_pwm.0\:0/duty_ns Будет указываться время самого импульса.
Проверить можно опытным путем. Возможно я найду или кто-то подскажет способ сделать это более красиво =)
Теперь осталось только активировать подачу сигнала.
echo 1 > /sys/class/pwm/gpio_pwm.0\:0/run И мы получаем на осциллографе что-то вроде этого


Если подключить к выводу PWM кабель сервопривода — он встанет ровно в центральное положение. Разумеется, питание тоже нужно подключить.

Заключение


Таким способом можно добиться генерации сигнала на частоте 200 Гц, а это означает что время реакции для одного привода снизится до 5 мс. Для открывания-закрывания замка, может, и не критично, а вот для летательных аппаратов будет весьма актуально. Надеюсь что я обзаведусь в ближайшее время мотором и контроллером, либо добрый читатель из города Екатеринбург согласится одолжить мне такой для экспериментов и появится вторая статья.
Спасибо что дочитали до конца. На закуску позвольте представить вам немного видео.

Демонатрация работы. Два канала, настроенные на крайнее правое и крайнее левое положение.


Видеодемонстрация ШИМ сигнала.


P.S.


Хочу выразить огромную благодарность автору модуля Claudio Mignanti, который ответил по почте и разъяснил необходимые вопросы.

Схема сервопривода и управляющих сигналов были взяты на wiki.amperka.ru.

Если у вас есть какие-то дополнения или пожелания — пишите в комментариях.

UPD: a5b интересуется что за устройство было использовано. Ну, это никакой не секрет. Плата — китайский аналог EL-M150. Процессор внутри — Atheros AR9331.
Он используется очень широко в таких распространенных роутерах как mr3020 или wr703n.
Выглядит плата следующим образом.
  • +30
  • 32,9k
  • 7
Поделиться публикацией

Комментарии 7

    +1
    Спасибо за познавательную статью. У меня следующие вопросы: На сколько точно устанавливается длительность сигнала и не плавает ли она (при наличии других процессов)? На сколько быстро можно менять длительность импульса ШИМ?
      0
      Пожалуйста!

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

      Скажите какой сценарий вам интересен — потестирую. Я еще в самом начале пути и не представляю пока как буду отлаживать это дело ).
        0
        UPD: На сколько я понял, вам интересно использовать ШИМ для управления яркостью. Это вполне реально. Devboard который мне прислали китайцы имеет светодиоды параллельно с GPIO. Я поначалу игрался и смотрел как меняется яркость. Камера фиксирует легкое моргание светодиода, не раздражает.
          0
          Вот так выглядит на 130 кГц.
          Погрешность около 9 нс.

          Но это xoscope через аудиокарту. Может чуток врать вполне и он.
            0
            Опечаточка. Там 1,3 кГц.
          0
          Очень не плохой результат! Если Вы планируете использовать OpenWRT для полетов я бы посоветовал проверить как сильно плавает сигнал при загрузке процессора (например с запущенным модулем mjpg-streamer).
            0
            Да, в планах провести нагрузочное тестирование и выложить во второй части статьи.

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

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

          Самое читаемое