Написание алгоритмов наверное самая для меня интересная часть в домашней автоматизации. Но даже вся масса сенсоров и сценариев не справляется с буйной фантазией жизни и приходится добавлять способ непосредственного контроля. В качестве органов ручного управления можно поставить и обычный дверной звонок, но что делать если хочется большего? Встречаем героя этой статьи — датчик жестов на основе SI1143 от Silicon Labs.
Сам SI1143:
Выглядит и правда футуристично.
А сколько достоинств:
- высокочувствительный фотодиод, малошумящий АЦП
- драйвера светодиодов с током от 6 до 360 миллиампер
- питание от 1.71 до 3.6 вольта
- и шустрый I2C — до 3.4 мегабит в секунду
Вот только размер подкачал всего 5 на 3 миллиметра. Такое и разглядишь то не с первого раза. Ну ладно тут нужно ещё немного обвязки.
А можно это убрать? Спросило моё чувство прекрасного. Я потом постараюсь удовлетворить просьбу этого редкого в наших краях гостя и спрятать плату в корпус, а пока можно подать питание и посмотреть что-же получилось.
Комментарий для внимательных. Тут действительно несколько больше деталей чем ожидалось. В качестве основы была взята нода из проекта Enviriot. Кроме микроконтроллера STM32F051 на плате установлен так-же приёмопередатчик на 868 мегагерц CC1101 от Texas Instruments и после заливки firmware достаточно подать питание и устройство подключится к MQTT-SN серверу.
Принцип работы основан на измерении уровня отражённого сигнала от каждого из 3 светодиодов. Попробую включить и посмотреть на отклик.
Из-за несимметричного расположения светодиодов сигнал от LED 1 заметно больше и придётся первым делом результаты измерений нормировать.
А вот так зависимость уже вполне понятна. Попробуйю закодить следуюший алгоритм:
A | B | C | D | |
---|---|---|---|---|
===> |
L1+ L3+ L1>L3 |
L1- L3+ L1>L3 |
L1- L3+ L1>L3 |
L1- L3- L1<L3 |
<=== |
L1- L3- L1<L3 |
L1+ L3- L1<L3 |
L1+ L3- L1<L3 |
L1+ L3+ L1>L3 |
Где L1+ — сигнал от LED 1 возрастает, L1>L3 — сигнал от LED 1 больше сигнала от LED 3.
Гладко было на бумаге, а вот в динамике начались проблемы. Для листа белой бумаги зафиксированного на одной высоте ожидаемые результаты получались в двух случаях из трёх. При попытке помахать руками сигнал начинает прыгать и мой замечательный алгоритм начинал путаться в показаниях. Посмотрел на руку, ну да от плоского листа белой бумаги отличий много. Но как-то оно должно работать. Ладно. Уговорили! Попробую прочитать документацию.
Для страждущих Silicon Labs выпустила AppNote AN580 — «INFRARED GESTURE SENSING». Описаны 2 основных метода определения жестов и их возможные комбинации. Первый метод — это определение позиции на каждый момент времени и на основе координат определение жестов. Во втором методе определяется сдвиг фаз между сигналами. Уже опробован был один из вариантов первого метода и он не впечатлил. Попробую реализовать второй.
Поехали. Нужно реализовать аж целых два пункта. Определить момент входа и передать эти данные в конечный автомат. Порог входа был определён экспериментально в 1/8 от полного сигнала. Для защиты от шума добавлю триггер Шмидта, включение на 15% и отключение на 10%.
Ну и сам конечный автомат. Состояния с 1 по 3 — движение вверх, состояния -1 по -3 — движение вниз и состояние 4 на тот маловероятный случай, если сработают оба LED одновременно.
А теперь попробуем со всем этим взлететь.
var LSt = new Int8Array([-3, -3, -3, 1, 1, 3, 3, 4,
-3, -3, -1, -1, 3, 3, 3, 4,
-2, -2, -2, 4, 2, 2, 2, 4]);
/* ...... */
this.r1 = false; this.r3 = false;
this.button = new Int8(0);
/* ...... */
if(n1 > 15) { this.r1 = true; } else if(n1 < 10) { this.r1 = false; }
if(n3 > 15) { this.r3 = true; } else if(n3 < 10) { this.r3 = false; }
let st = (this.r1?1:0) | (this.r3?2:0);
if(st == 0){ // Оптимизация. На Нет и ответа нет
this.button = 0;
} else {
this.button = LSt[st*8 + this.button - 5];
}
В переменных n1 и n3 лежат нормализованные значения для соответствующих светодиодов. Результат находится в поле button.
Для дальнейшего использования полезны состояния 2 — вверх и -2 — вниз.
Программа пишется на подмножестве JavaScript, потом компилируется в bytecode и заливается на устройство. Разбором JavaScript и генерацией AST занимается библиотека NiL.JS от камрада IaIojek, за что ему огромное спасибо.
Если состояние 2 длится меньше 0.3 секунды, за это отвечают блоки А14 и А15, яркость выставляется на максимум. Блоки А01 и А13 выставляют яркость в 0 при кратковременном движении вниз.
При движении вверх и удержании блоки А10, А09 и А04 обеспечивают плавное увеличение яркости. При движении вниз и удержании работают блоки А12, А11 и А08 и позволяют уменьшить уровень.
Демонстрация работы. 20 Мегабайт гифка.
Ну вот пожалуй и всё. Заказчик довольна, а я начинаю думать над следующей версией. Из необходимых изменений: расположить светодиоды на одинаковом расстоянии от приёмника, вывести индикацию срабатывания и сделать опрос на отдельном контроллере, что позволит уменьшить интервал опроса.