WS2812B + APDS9960 = управляемый жестами светильник на Arduino

8 января 2020

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

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

Описание светильника

Основной упор в этом светильнике я сделал не на визуализацию, а на управление жестами, все остальные функции второстепенные.

Включается светильник жестами влево или в право, а так же можно включить и жестом на себя, но это не совсем удобно. Далее жестами влево и в право можно перелистывать световые эффекты. Если начать листать вправо, то лампа сначала будет менять свои цвета от белого до красного, включая все основные цвета и переходы между ними.
Если после включения лампы начнем листать влево, то увидим динамические световые эффекты, такие как “Огонь” , “Матрица”, “Лава лампа”, “Радуга”, “Конфетти”, “Искры”, “Огненный светильник”. Если Вам нужно вернуться на обычный светильник, то вместо перелистывания, можно выключить лампу жестом от себя и включить любым из трех жестов.

Выключение производится жестом от себя.

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

Я не уделял особого внимания визуальным эффектам, так как планирую сделать вторую версию лампы на контроллере Wemos D1 mini. В которой планирую довести все до идеала. По этой же причине я пока использую только одну линейку светодиодов, состоящую из 4 планок ws2812b, вместо четырех.

Прерывания APDS9960

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

Сначала попробовал исправить проблему изменениями в железе. Фильтрация питания не помогла, даже от аккумулятора 18650 датчик все равно продолжал жить своей жизнью. Попробовал переключить нагрузочный резистор сигнала INT на +5 В и это тоже не принесло успеха.

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

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

Определение жеста

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

Для того, что бы улучшить стабильность распознавания жестов, так же пришлось в библиотеке уменьшить чувствительность приемника. Для этого нужно в файле SparkFun_APDS9960.h заменить строку:
if( !setLEDBoost(LED_BOOST_300) )
на
if( !setLEDBoost(LED_BOOST_150) )

Если Вы скачали библиотеку из этой статьи, то ничего делать не нужно, там уже все исправлено.
Я так же экспериментальным путем подобрал ток светодиода 50 мА, при котором жесты определяются наиболее стабильно и нет надобности насиловать инфракрасный светодиод, током 100 мА.

А так же я допустил ошибку, разместив микроконтроллер в нижней части светильника, а датчик жестов в на верхней крышке. Из-за этого, для соединения arduino и apds9960, пришлось использовать провода длинной 30 см. Что тоже добавило дополнительной нестабильности работы датчика. В итоге я программным путем победил все эти проблемы.

Схема

Для питания устройства я использую зарядное устройство от моего смартфона, с напряжением выхода 5В и током 2А. Но на самом деле светильник при включенном белом свете на максимальной яркости, не потребляет выше 1,3 А. По этому подойдет любой источник питания с выходным током не менее 1,3А.

Стабилизатор dc-dc mini360, можно заменить на любой другой понижающий преобразователь напряжения, с выходным током не менее 150 мА.

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

Вместо Ардуино Нано можно использовать контроллер ;Arduino UNO или его клоны.

Обязательно проверьте на датчике жестов наличие перемычек, они отмечены красным цветом на фотографии ниже. В случаи их отсутствия следует паяльником на эти контактные дорожки, нанести и разогреть припой, до образования однородной капли. Сейчас китайцы поставляют эти датчики без перемычек. Без указанных перемычек работа датчика не гарантируется.

Используемые компоненты

Arduino Nano – 1 шт.
Датчик жестов APDS9960 – 1 шт.
Светодиодные планки ws2812b – 4 шт.
Преобразователь понижающий mini360 – 1 шт.
Соединительные провода – 1 комплект.

Программный код для Ардуино

Код разбит на две части. В первой части находится основной код, который работает с сенсором, а во второй части находится код всех световых эффектов. Вы можете сами добавить любой эффект по аналогии с моим кодом, но главное не забудьте добавить функцию выхода по жесту из зацикленного эффекта. Для этого нужно добавить в конце цикла, следующую строку if(check_int()) return;

Описание основных функций программы

processingGesture() - обрабатывает прерывания от датчика жестов.
processingProximity() - обрабатывает прерывания от датчика приближения.
gesture_int() – обработчик прерывания от датчика жестов.
proximity_int() – обработчик прерывания от датчика приближения.

Описание констант

APDS9960_INT – вход для внешнего прерывания. В Arduino Nano и UNO всего два таких входа, 2 и 3.
PIN – здесь нужно указать выход на светодиодную ленту. Можно указывать любой цифровой пин к которому подключены планки ws2812b.
NUM_PIX – здесь указываем количество адресных светодиодов в используемой ленте.
range – предел погрешности от 0 до 10. Если при регулировке яркости зафиксировать руку над датчиком на 2 сек, то показания должны сохраниться, если же показания не сохраняются, то увеличивайте постепенно предел погрешности.

Скачать библиотеку APDS9960
Скачать скетч светильника

Итоги

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

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