Cubietruck. Практические применения

от автора

Здравствуй, Хабр!

4 месяца и два дня прошло с момента первой моей публикации «Cubietruck. 15 поводов приобрести», которая к сожалению зависла в песочнице, хотя и периодически всплывает при поиске в Google.
Очень странно, что на Хабре еще нет новых статей по запросу «Cubietruck». Может быть народ смущается покупать эту железку, не зная ее возможностей?
Сегодня мы этот пробел исправим.
Мы даже перешагнем через стереотип первого классического топика о возможностях железок, не будем моргать светодиодом в классическом понимании, а сразу сделаем чего-нибудь интересного. Например интерактивный выключатель света. А заодно и научимся работать с инфракрасным портом на простом английском языке.

Какой у нас план?

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

Что нам для этого нужно?

— Сложных систем обнаружения на основе OpenCV или ViBe мы пока проектировать не будем, а вместо этого используем старый дедовский способ — движение наших тел.
— Для резервного управления, пригодилась бы консоль\планшет, но их таскать с собой очень неудобно, а ложиться спать, перед этим отмонтировав что-нибудь — это не тру. Поэтому нам нужен пульт ДУ. Забегая наперед, скажу что пульт подойдет любой, от любого устройства. Лишь бы был рабочим, и с ИК.
— Нам нужно целевое устройство, которое мы будем мучать. Пусть это будет какая-нибудь лампа. Или даже светодиод, если мы боимся лезть в 220 В.
— А еще нам нужны коммутаторы, для подачи питания на эти самые реле.
— И конечно же, нам нужен Cubietruck с адекватной ОС на нем. Под адекватной ОС я имею в виду систему, которая скомпилирована со всеми драйверами, устройствами, и почти не требует обработки напильником.

Что у нас есть ?

— У нас есть PIR датчик движения. Выглядит он вот так.
image

Выдает на выходе ноль, если движения нет, и единицу на протяжении нескольких секунд, если движение есть. Под единицей подразумевается 3.3 вольта, что очень важно для нас, ибо Кубик не толерантен к 5В.

— У нас есть пульт ДУ от DLP проектора Viewsonic. Не очень большой, и не очень маленький. Нам сойдет.

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

— У нас есть двухрелейный блок, который я покупал к Ардуине (не думайте обо мне ничего плохого). Он принимает на свои два входа единицу или ноль, и в зависимости от этого, включает или выключает реле. Реле кстати 250В/10A, что есть хорошо.

— И наконец у нас есть Cubietruck.

Поехали !

Не буду останавливаться детально на методах установки ОС на Кубик, вкратце скажу что это Cubian (Дебиан), скачанный с официального сайта (http://cubian.org/downloads/), с небольшими костылями, а именно:
Модуль bcmdhd, который необходим для работы wifi, не запускается, если его прописать в /etc/modules, поэтому его пришлось прописать как modprobe bcmdhd в /etc/rc.local;
В /etc/modules пришлось добавить модуль sunxi-ir, это модуль для работы инфракрасного порта;
Wicd, который стоит там по дефолту, в упор не видел наличие вайфая, даже когда я вручную его сконфигурил и сидел с кубика в интернете. Пришлось в том же /etc/rc.local прописывать вручную поиск точки доступа, подключение к ней, и получение IP-адреса.
В общем небольшие костыли.

Теперь нам нужно проверить базовые способности нашей системы, при помощи консоли, а лучше через SSH (стандартный логин ОС — cubie, pw: cubie). Из под рута:

root@Cubian:/home/cubie# lsmod Module                  Size  Used by bcmdhd                541066  0  cpufreq_conservative     5720  0  cpufreq_powersave       1242  0  cpufreq_userspace       3532  0  cpufreq_fantasy         3855  0  disp_ump                 854  0  mali_drm                2638  1  drm                   213650  2 mali_drm mali                  113847  0  ump                    57087  4 mali,disp_ump gpio_sunxi              8593  59  sunxi_ir                4037  0  

Для наших целей должны быть обязательно загружены два последних модуля.
Они у нас загружены, и мы готовы двигаться дальше…

cd /dev/input root@Cubian:/dev/input# ls -l total 0 drwxr-xr-x 2 root root     60 Mar 16 21:05 by-path crw------- 1 root root 13, 64 Mar 16 21:05 event0 crw------- 1 root root 13, 65 Mar 16 21:05 event1 crw------- 1 root root 13, 63 Mar 16 21:05 mice 

Это список наших устройств ввода. Нас интересуют файлы event*, это устройства-файлы событий, которые происходят при действии устройства ввода. Кто-то из них — наш инфракрасный порт. Это легко проверить с помощью
root@Cubian:/dev/input# cat event1 | hexdump

Теперь если мы нажмем что-нибудь на пульте ДУ, то должны получить примерно следующее:

0000000 28b2 5326 2723 000e 0001 0085 0001 0000
0000010 28b2 5326 272d 000e 0000 0000 0000 0000
где 5326 — код нашего пульта, а 0085 — код нажатой клавиши.

Пульт работает, можно разбираться с GPIO.

Система портов ввода-вывода в этих устройствах для меня непонятна, и пришлось вечерок покурить спеки к Кубику и процессору А20, чтобы понять что к чему.

Итак, приблизительный алгоритм моргания светодиодом следующий:
— активируем необходимый пин. Они ведь многофункциональные. Делается это при помощи например echo 8 > /sys/class/gpio/export
— смотрим, активировался ли этот пин в sysfs…

root@Cubian:/sys/class/gpio# ls /sys/class/gpio | grep gpio8 gpio8_pg2 

— идем в спек (http://linux-sunxi.org/Cubietruck#Expansion_Ports), ищем, на какой реальной ноге находится наш PG2. Он на ноге 5, разъема CN9. Это разъем, находящийся возле USB-порта. В дальнейшем, я постараюсь использовать нумерацию ног с реальной платы, а если кому-то интересно, на этом ресурсе можно прочитать что на этой ноге находится.

— даем ОС понять, что пин будет работать на вывод, echo out > /sys/class/gpio/gpio8_pg2/direction
— подключаем что-нибудь тестер на ногу 5.

— посылаем вывод на эту ногу echo 1 > /sys/class/gpio/gpio8_pg2/value
Напряжение изменилось. Работает. Можно разворачиваться.

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

#!/bin/sh d=`date` for i in `seq 1 11`;do echo $i > /sys/class/gpio/export echo "GPIO # $i initialized" sleep 0.5 done  for i in `seq 16 24`;do echo $i > /sys/class/gpio/export echo "GPIO # $i initialized" sleep 0.5 done  for i in `seq 28 61`;do echo $i > /sys/class/gpio/export echo "GPIO # $i initialized" sleep 0.5 done  for i in `seq 64 67`;do echo $i > /sys/class/gpio/export echo "GPIO # $i initialized" sleep 0.5 done  c=`ls /sys/class/gpio` echo "[$d]" >> /var/log/gpio.log echo "$c" >> /var/log/gpio.log echo "[/$d]" >> /var/log/gpio.log sleep 1 

Этот скрипт я запускаю из /etc/rc.local, для удобства сделал вывод в лог.
Вы сразу же заметите, что пины назначаются странным образом, некоторые пропускаются. Именно так, при попытке инициализировать их, система зависает намертво. Причину точную не знаю, скорее всего на этих пинах что-то висит, wifi или даже mmc карта.

Вроде разобрались с инфракрасным портом, и GPIO. Настало время подключить реальные железки.
Модуль реле подключается стандартно, у него всего три выхода: +5В, земля, и сигнал. Землю я беру с одного из пинов UARTa, можно брать откуда угодно. Плюс 5В я беру с 29-го пина, разъема который находится ближе к LAN. Сигнальный провод мы будем подключать к пину 9, разъема куда мы уже подключали наш тестер (ближе к USB, напомню).
Чтобы не отвлекаться на это потом, сразу же подключим наш датчик движения. У него тоже три выхода, +5В, земля и сигнал. Питание подключаем туда же, куда и релейное. А сигнал подключим к 7-му пину, рядом с девятым.
Конечная конструкция, вид спереди:

Теперь нам надо подключить пульт.
Первое что мне (и наверное вам) пришло на ум — lirc. Приблуда для управления инфракрасным портом. Не подходит. Сложно. Почему — смогу написать в комментах, если повезет. Решение мы возьмем простое, но самописное.
Мы будем использовать python, напару с его волшебной библиотекой evdev, для работы с линуксовыми /dev-устройствами.
Ставим вначале pip (питоновский внутренний установщик, кто не в курсе): apt-get install python-dev
Уже с pip ставим библиотеку evdev: pip install evdev
Вуаля, готово.

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

import string  from evdev import InputDevice from select import select  dev = InputDevice('/dev/input/event1')  while True:    r,w,x = select([dev], [], [])    for event in dev.read():         if event.type==1 and event.value==1:                 open('/dev/irda', 'w').write(str(event.code))  

Этот скрипт считывает ивент устройства ввода (мы выше определили, что у меня это /dev/input/event1) и записывает код ивента в файл /dev/irda. Для удобства.
Не знаю как так совпало, но этот скрипт при нажатии разных клавиш пульта, возвращает разные коды. Это неправильно. По-хорошему, нужно уметь различать код кнопки и код пульта, но это будет позже, наша главная цель — Кубик.

У нас получился файл /dev/irda, в котором всегда хранится код последней нажатой клавиши.
Запускаем этот скрипт, сворачиваем в background по CTRL+Z, и тестируем

root@Cubian:/home/cubie# cat /dev/irda 132 

Теперь у нас есть мини-демон, который отслеживает нажатия с пульта, и записывает его в /dev/irda. И ниже мы узнаем, зачем нужен был этот костыль.

Обрабатывать события от пульта, мы будем на самом простом и понятном всем языке — английском bash. Скрипт irda.sh.

#!/bin/bash echo out > /sys/class/gpio/gpio4_pg6/direction  while [ 1=1 ];do if [ -e /dev/irda ];then code=`cat /dev/irda` rm /dev/irda  if [[ "$code" = "132" ]];then echo 1 > /sys/class/gpio/gpio4_pg6/value fi  if [[ "$code" = "135" ]];then echo 0 > /sys/class/gpio/gpio4_pg6/value fi  if [[ "$code" = "101" ]];then c=`cat /dev/movement`  echo out > /sys/class/gpio/gpio67_ph7/direction  if [[ $c = "1" ]];then  echo 0 > /sys/class/gpio/gpio67_ph7/value  echo 0 > /dev/movement  else  echo 1 > /sys/class/gpio/gpio67_ph7/value  echo 1 > /dev/movement  fi fi echo $code                         fi sleep 1 done 

Я не программист, поэтому сорри за отступы, попробую пояснить, какой алгоритм я хотел сделать.
Раз в секунду, в бесконечном цикле, программа проверяет наличие файла /dev/irda.
Как только она его находит, она считывает значение нажатой клавиши, и тут же удаляет файл. Это самый простой способ избавиться от эффекта «залипания клавиши пульта», когда программа постоянно видит одно и то же значение.
Стоит отдельно упомянуть о костыле на Python. Он необходим (мне по крайней мере), потому что простой bash, при чтении event, ожидает ввод, и не сможет выполняться дальше, пока не будет событие нажатия.
Одной кнопкой пульта, реле включается. Другой кнопкой — выключается, это можно легко проследить в скрипте.
Последнее условие, с кодом «101» — нам понадобится позже, для выполнения всех пунктов плана. В общих чертах, этот блок оставляет в системе признак вкл\выкл.

Теперь запустив этот скрипт, мы можем поклацать реле. Оно клацает. С пультом мы разобрались.

Нас ждет датчик движения, подключенный к пину №7.
Определять движение намного проще, чем нажатие на пульте. Для нетерпеливых, простой скрипт, а объяснение позже. Итак, move.sh

#!/bin/bash echo in > /sys/class/gpio/gpio6_pg4/direction echo out > /sys/class/gpio/gpio4_pg6/direction echo 1 > /sys/class/gpio/gpio4_pg6/value  while [ 1=1 ];do c=`cat /dev/movement` if [[ "$c" = "1" ]];then code=`cat /sys/class/gpio/gpio6_pg4/value` if [[ "$code" = "1" ]];then echo 0 > /sys/class/gpio/gpio4_pg6/value sleep 20 echo 1 > /sys/class/gpio/gpio4_pg6/value                        fi                     fi sleep 1 done  

В этом скрипте мы так же само инициализируем пин 7 на ввод (вторая строчка), пин 9 на выход, и в бесконечном цикле ждем, пока в файле /sys/class/gpio/gpio6_pg4/value появится единица, затем на 20 секунд включаем реле, и отключаем. Отдельно стоит упомянуть, что проверка движения произойдет, только если в системе находится признак «вкл», о котором говорилось выше. Такой себе чит.

Собственно, на этом все.
Запустим все три файла:

python irda.py & ./irda.sh & ./move.sh 

Подвигаемся перед датчиком движения. Работает.
Включенный во время движения свет, можно отключить нажатием кнопки на пульте, а выключенный — включить. Здесь есть очевидные минусы — скрипт обработки движения всегда выполняет действие последним. То есть если через 20 секунд после движения, свет выключился, мы его включили с пульта и опять выключили принудительно — свет включится во время движения.

Чтобы этого избежать, и был введен чит с /dev/movement. Третьей кнопкой на пульте, попросту отключается система определения движения. Управление с пульта остается рабочим, и детектор движения может быть активирован повторным нажатием кнопки. Для индикации режима, я добавил в скрипт irda.sh работу с /sys/class/gpio/gpio67_ph7. Это зеленый светодиод на Кубике, который будет светиться, если система реагирования на движение активна.

В лучших традициях Хабра, видеопруф.

Youtube:

VK:
vk.com/video21800443_168125094

P.S. Прошу прощения за отвратное качество фото и интерьера, эксперименты изначально не планировались для Хабра.

ссылка на оригинал статьи http://habrahabr.ru/post/216211/


Комментарии

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

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