Сделай сам себе ардуину: Часть 1 – ATMega

Поскольку Arduino – это открытая платформа, то каждый встрченый-поперечный может сделать себе Arduino сам.
На сайте Arduino в общем-то даже есть инструкция.
Вот, например, видео в котором показан примерный процесс

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

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

Меня это момент заинтересовал и я решил попробовать сделать себе Arduino на макетке. Всё, как и на видео выше, очень просто, с той лишь разницей, что я купил микросхему ATmega328p-pu без bootloader-а.

20160205_205831Одна микросхема ATmega328p-pu, один кристалл на 16 Mhz, два конденсатора на 22 пикофарад и резистор – вот и весь Arduino Uno. Да у него нет USB и ещё много чего вроде самовостанавливающегося предохранителя, но для конечного проекта этого как правило и не важно.

Чтобы собрать такой Arduino нужно вставить 16 МГц кристалл между 9 и 10 ножками. Два конденсатора идут между землёй – ножка 8 и ножками кристалла, например один конденсатор между и 10й, а второй между и .

Сначала нужно залить скетч ArduinoISP в тот Arduino, который будет выступать в качестве программатора.

ArduinoISPЗатем поменять настройки и выбрать плату в которую будут заливаться скетчи, а в качестве программатора выбрать Arduino as ISP. Залить bootloader используя Arduino Uno, соединив контакты следующим образом (для Arduino Uno/Nano)

D10 -> Reset (Первая нога)
D11 (MOSI) -> MOSI (17я нога)
D12 (MISO) -> MISO (18я нога)
D13 (SCK) -> SCK (19я нога)

и добавив конденсатор на Arduino Uno, который используется в качестве программатора, между Reset-ом и землёй.

nanoviauno 20160211_210204

Теперь можно заливать Sketch-и в Arduino у которых поломан или отсутствует USB.

Вот, например, мой проект по мониторингу качества воздуха работает на самодельной Arduino Uno собранной на макетной плате:

IMG_20160206_153044Но что если хочется ещё меньше? Первое, что попалось мне в интернете это ATTiny45/85:

Собственно работает неплохо. Например я собрал простенькую схему для управления светодиодами на основе ws2812b:

20160117_204324Так любимая мной шина i2c тоже работает но с некоторыми переделками.

Схема подключения для программирования с использованием Arduino Uno в качестве программатора аналогична подключению к Arduino Nano, достаточно посмотреть распиновку для ATTiny в Googl-е:

20160407_135833 20160407_140704

Другая альтернатива – это Arduino Nano или ATmega328p-au, которая немного больше ATtiny, но полнофункиональна как ATmega328p-pu на Arduino Uno.

20160206_12302120160227_124652

Мне понравился вариант SEM0010, который идёт сразу с большой макетной областью:

20160206_123029Минусом является то, что отсутствует USB для заливки скетчей, однако тут тоже можно использовать другой Arduino в качестве программатора. К тому же тут есть ICSP разъём, что позволяет подключить её без пайки. Вот например простейший пример Blink, залитый через ICSP:

20160227_165127Собственно ICSP это те же самые MOSI/MISO/SCK, так что по прежнему используются pin-ы с 10 по 13й на Arduino, которая выступает в качестве программатора. Кстати если вы откроете стандартный sketch ArduinoISP вы даже найдёте там описание того, как использовать Arduino в качестве программатора.

Ещё один вариант миниатюризации – это Искра Мини от Амперки.

20160315_150541Это та же ATMega328p-au, так что с ней можно работать так же как и с Arduino Nano.

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

Если вам интересно, есть что добавить или покритиковать – не стесняйтесь оставлять комментарии.

Будильник своими руками: Часть 1 – Время, дата и день недели

Сейчас у всех есть телефоны и традиционные часы-будильники уже не так популярны, однако производители таких девайсов не сдаются и продолжают придумывать фишки, которые бы позволили им оставаться на плаву. Например, светобудильник, который синхронизируется с IPhone-ом:

20160305_220218Фактически это будильник + док станция. Я решил что мне нужен наподобие, только для Android-а… с беспроводной зарядкой… какой-нить весёленькой индикацией событий в телефоне… Ну и добавлю ещё каких-нить свистелок-перделок.

Первое, что нужно сделать – это конечно сами часы. Купил индикатор и часы реального времени (RTC) с батарейкой cr1220.

20160305_160942 20160305_160952

разместил это дело на макетке и подключил к Arduino

20160305_221732нашёл на сайте Амперки примеры для работы с часами реального времени и индикатором. Скачал библиотеки, необходимые для работы с ними и сделал простой скетч, который просто установил бы текущее время. Получилось примерно вот так:

20160305_222041Следующим шагом добавил кнопку, для изменения отображаемой информации и зуммер для индикации успешного нажатия. Для добавления Зуммера в свой проект не требуются дополнительной библиотеки – можно воспользоваться встроенной функцией tone.

Кнопку пока сделал как переключатель между временем, датой и днём недели. То есть по умолчанию “будильник” показывает часы и минуты, нажимаешь на кнопку – показывает дату, нажимаешь ещё раз – показывает день недели и так по кругу.

Вот как это выглядит и работает:

Ниже приведён полный исходный текст программы.

// библиотека для работы I²C
#include <Wire.h>
#include <QuadDisplay.h>
// библиотека для работы с часами реального времени
#include "TroykaRTC.h"

// EEPROM — энергонезависимая память
// библиотека для записи и считывания информации с EEPROM
#include <EEPROM.h>

// размер массива для времени с учётом завершающего нуля
#define DISPLAY_PIN 7 // Ножка QuadDisplay-я
#define KEY_PIN 8  // Ножка для кнопки
#define MODE_NUM 3  // Количество вариантов отображения инфы
#define FREQ 250  // Задержка в основном цикле
#define BUZ_PIN 11  // Ножка для зуммера

// создаём объект для работы с часами реального времени
RTC clock;

unsigned short mode = 0;

uint8_t dot = 0x4;

void setup()
{
  pinMode(KEY_PIN,INPUT);
  pinMode(BUZ_PIN,OUTPUT);

  Serial.begin(9600);
 
  // инициализация часов
  clock.begin();
  // метод установки времени и даты в модуль вручную
  // clock.set(10,25,45,27,07,2005,THURSDAY);
  // метод установки времени и даты автоматически при компиляции
  //clock.set(__TIMESTAMP__);
}

void loop()
{
  // Проверяем нажата ли кнопка
  if (digitalRead(KEY_PIN) == HIGH)
  {
    // Меняем индекс отображаемой инфорамции
    mode++;
    // Издаем короткий звук для подтверждения что нажатие кнопки считано
    tone(BUZ_PIN, 3500, 40);
  }

  // Проверяем не вышел ли наш индекс за границы
  if (mode == MODE_NUM)
    mode = 0;  // Если да то меняем на начальный

  // запрашиваем данные с часов
  clock.read();

  if (mode == 0)
    DisplayHourMinute(); // Отображаем Часы и Минуты
  else if (mode == 2)
    DisplayDate();  // Отображаем день и месяц
  else
    DisplayDay();   // Отображаем день недели

  delay(FREQ);
}

void DisplayHourMinute()
{
  int hm = clock.getHour() * 100 + clock.getMinute();  
  uint8_t dot = 0x4;  // Нам нужна точка между второй и третьей цифрами
  uint8_t sec = clock.getSecond();
  if (sec % 2) // Для эффекта мигания отображаем точку только
    dot = 0x0;  // на нечётной секунде
 
  displayInt(DISPLAY_PIN, hm,true,dot);
}

void DisplayDate()
{
  int dm = clock.getDay()*100 + clock.getMonth();
  displayInt(DISPLAY_PIN, dm, true, 0x4);
}

// Ниже я просто отображаю константы заданные в .h файле
// для часов, чтобы получились три буквы дня недели...
// ну или что-то похожее
void DisplayDay()
{
  uint8_t dow = clock.getDOW();
  if (dow == 7)
    displayDigits(DISPLAY_PIN, QD_NONE, QD_S, QD_U, QD_n);
  else if (dow == 1)
    displayDigits(DISPLAY_PIN, QD_NONE, QD_H, QD_O, QD_n);
  else if (dow == 2)
    displayDigits(DISPLAY_PIN, QD_NONE, QD_t, QD_U, QD_E);
  else if (dow == 3)
    displayDigits(DISPLAY_PIN, QD_NONE, QD_H, QD_E, QD_d);
  else if (dow == 4)
    displayDigits(DISPLAY_PIN, QD_NONE, QD_t, QD_h, QD_u);
  else if (dow == 5)
    displayDigits(DISPLAY_PIN, QD_NONE, QD_F, QD_r, QD_I);
  else
    displayDigits(DISPLAY_PIN, QD_NONE, QD_S, QD_a, QD_t);
    
}

Ещё одна полезная функция – это датчик влажности и температуры на основе уже знакомого мне DHT22.

20160130_130724Добавить его в проект не составляет труда: требуется один дополнительный пин,

#define DHT_PIN 6

новый объект для работы с датчиком,

#define DHT_TYPE DHT22

DHT dht(DHT_PIN,DHT_TYPE);

две процедуры DisplayTemperature() и DisplayHumidity(), которые будут отображать температуру и влажность соответственно и будут работать аналогично DisplyaHourMinute()

void DisplayHumidity()
{
  float h = dht.readHumidity();
  displayFloat(DISPLAY_PIN, h, 2, true);
}

void DisplayTemperature()
{
  float t = dht.readTemperature();
  displayFloat(DISPLAY_PIN, t, 2, true);
}

и изменение количество вариантов отображаемой информации с 3х на 5, так как устройство теперь может показывать температуру и влажность.

#define MODE_NUM 5

Правда на половинной макетке, которую я использовал для прототипирования закончилось место, и я решил воспользоваться Troyka Shield-ом для прототипирования, для того, чтобы вынести часы реального времени и зуммер и освободить место для датчика влажности и температуры:

20160329_224355И хотя конечная цель проекта – это спарить Arduino с Android-ом, думаю что возможность устанавливать дату, время и будильник независимо от наличия телефона тоже пригодиться.

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

Простой сетевой код под Android

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

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

Итак, Задача. Есть некий сервис, который сидит и ждёт команду… строчку. Известен IP и порт. Клиент например на perl-е тривиален:

use strict;

use IO::Socket::INET;

my $sock = new IO::Socket::INET(PeerAddr => '192.168.1.48',
                                PeerPort => '6969',
                    Proto => 'tcp') || die "Can't bind $@\n";


$sock->send(shift."\n");

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

Итак, с чем же я столкнулся? Казалось бы что тут сложного, открываем google и ищем что-нить типа How to send tcp packet in Android. Первая же ссылка выглядит вполне прилично. Читаем внимательно. Ок, делаем простое приложение, не забывая о правах для этого самого приложения

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

и… оно крашится. Googl-им сообщение об ошибке и оказывается, сетевой код не может выполняться в основном треде и для него нужен AsyncTask, что в общем-то логично, но какой-нить Warning что ли не помешал бы.

Идём дальше. Скомпиляли, запустили на эмуляторе… ни хера не происходит. Кнопка жмякается, а серверная часть молчит… Толи этот AsyncTask ещё не выполнился, толи сервак не доступен толи хер знает чего.

Окей, сделал простой сервер на perl-е и запустил локально

use strict;

use IO::Socket::INET;

$| = 1;

my $soc = new IO::Socket::INET(LocalHost => '0.0.0.0',
    LocalPort => '6969',
    Proto => 'tcp',
    Listen => 5,
    Reuse => 1,);

die " Failed $!!" unless $soc;

while (1)
{
  my $client = $soc->accept();
  warn "accept: " .$client->peerhost();

  my $Data = "";
  $client->recv($Data, 1024);
  warn "$Data";
  shutdown($client,1);

}

$soc->close();

пробую подключится с эмулятора уже на perl-овый сервер, который работает на той же машине… и опять ничего. Что за… Опять гуглю и тут начинается: и Windows говно и не хватает прав и эмулятор говно… ладно… беру старый свой HTC телефон, опять начинают ставится Driver-а, вылезать HTC Sync Manager-ы, падать ADB, Android Studio то видит, то не видит телефон, то не может подключиться…

Через какое-то время, не знаю как, мне таки удалось запустить мое приложение на телефоне, и о чудо! Оно подключается к перловому серваку, но… ни хера не шлёт. В итоге, уже не помню как я к этому пришёл, заменил код, который отсылает строчку на отсылку байтов и вуаля – оно заработало как на видео в самом верху поста.

Итак, вот моя реализация. Делаем кнопку, OnClick которой собирает данные из разных текстовых полей (например IP-адресс), создает экземпляр AsyncTask и запускает его передавая туда IP и данные о цветах

            public void onClick(View v) {
                EditText etip = (EditText) findViewById(R.id.editText);
                EditText strData = (EditText) findViewById(R.id.testEditText);

                String ip = etip.getText().toString();
                String data = strData.getText().toString();

                ASColorSender asColorSender = new ASColorSender();
                asColorSender.execute(ip, data);
                final TextView tv = (TextView) findViewById(R.id.textView);
                tv.setText("done");
            }

и у нас имеется класс ASColorSender, который унаследован от AsyncTask и реализует один метод – doInBackground, который собственно и принимает переданные ему данные, устанавливает соединения с сервером и отсылает туда строчку с цветами:

public class ASColorSender extends AsyncTask<String,Void,Long> {
    @Override
    protected Long doInBackground(String... params) {
        String ip = params[0];
        String data = params[1];
        Socket socket = null;
        try {
            socket = new Socket(params[0].toString(), 6969);

            OutputStream out = socket.getOutputStream();
            out.write(params[1].getBytes());
            //PrintWriter output = new PrintWriter(out);

            //output.println("25;25;25;25;");//params[1]);

            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return new Long(1);
    }

отдельное “спасибо” авторам за extends AsyncTask<String,Void,Long>. Мало нам стандартных типов, давайте сделаем такие же только с блек джеком и шлюхами…

Резюмируя, видимо я не совместим с Java-ой или с разработкой под Android в принципе. Пока занимался этим проектом – пробовал некий Appcelerator, который должен сделать всё ещё проще и универсальнее, но это такой кусок говна, который ещё поискать надо. Смотришь в хелп, где написано, нажмите сюда и у вас появится пример приложения. Жмякаешь… и ничего не происходит. Там вообще много где кликаешь и ничего не происходит… Хоть бы какое сообщение типа чего не хватает или чего надо установить… но нет, просто грёбаное ничего…

Так к чему это я всё? Какой смысл в этом посте?

Если вдруг ты, случайный читатель, Java/Android девелопер и тебе вдруг нужен код, который отсылает TCP пакет, то пользуйся на здоровье. Вот.

Монитор качества воздуха своими руками: Часть 2 – Сделай мне красиво

В предыдущем посте получилось пркатически готовое устройство, хоть и располагается на макетной плате.

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

Для начала купил пластиковый корпус 100 на 100 на 40 с крышкой (взял на глаз). Оказалось, что Arduino Uno малость великоват,  для того, чтобы засунуть его в этот корпус вместе с батарейками (Кто бы мог подумать?), да и в целом ATmega328p-pu какая-то здоровая, поэтому решил искать варианты.

Первое что попалось на глаза – это ATTiny45, однако сходу перенести код не удалось, так как i2c тут реализован по-другому.

Следующим стал Arduino Nano. По сути тот же самый чип просто в другом форм факторе. Вот только Arduino IDE категорически отказывался заливать туда мои скетчи. Видимо через чур китайский

20160206_123021На просторах интернета был найден лёгкий способ бросить треску тебе в ебало мразь пример решения похожей проблемы. Собственно так я и сделал – поменял секцию Nano в файле boards.txt на нечто вроде этого:

nano.name=Arduino Nano

nano.upload.tool=avrdude
#nano.upload.protocol=arduino
nano.upload.using=arduino:arduinoisp

nano.bootloader.tool=avrdude
nano.bootloader.unlock_bits=0x3F
nano.bootloader.lock_bits=0x0F

nano.build.f_cpu=16000000L
nano.build.board=AVR_NANO
nano.build.core=arduino
nano.build.variant=eightanaloginputs

вариант подключения напрямую через USB так и не заработал, выдавая невнятное “did not find any USB device ‘usb'”, так что пришлось программировать Nano используя Arduino Uno в качестве программатора.

20160211_210204Отлично теперь всё работает, но тут я вспомнил, что у меня есть другой “девайс” со странным названием SEM0010 на ATmega328, который к тому же имеет макетную область. И о чудо – это практически Arduino Nano c ATmega328p-au и теми же 32мя контактами.

20160205_202226Единственное неудобство – это то что у него нет USB, поэтому его также пришлось перепрошивать используя Arduino Uno  в качестве программатора используя те же самые ножки и ICSP header на самом устройстве. Для проверки как обычно лучше всего походит пример blink:

20160227_165127Всё работает, так что залил свой скетч и стал припаивать датчики:

20160206_210002Заодно приобрёл и приделал к датчику пыли небольшой вентилятор, дабы тот протаскивал воздух через сенсор.

Вырезав в корпусе отверстия под датчик влажности и температуры на основе DHT22 и заодно окно под дисплей, стал впихивать всё это хозяйство в корпус.

20160206_20075020160206_222804

И вуаля – оно работает. Оказалось, правда, что я забыл сделать выключатель, поэтому пришлось воспользоваться зажимом типа “крокодил”. Позднее вставил маленький выключатель

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

20160211_221021Однако в коде обнаружилась бага – как не пытался я дымить на устройство и совать его в пыльные места, так и не получилось, чтобы он показывал что-то отличное от нуля намекая, что воздух в Москве кристально чистый.

Заново подключил к Arduino Uno, сняв заднюю крышку:

20160227_171928Попробовал пример от производителя Waveshare, но он показывает какие-то фиксированные значения, и прыгает от “идеальное качества воздуха” до “сильно загрязнённое” – ему веры нет. К тому же, посмотрев в код, я увидел, что там значения домнажаются на какие-то ничем не обоснованные константы, так что ну его нафиг.

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

Последняя попытка привела меня на ещё один сайт с подобным проектом, где тоже есть непонятные мне домножения. Посмотрев ещё раз в Datasheet, я решил сделать очень просто. Выводить значение считанное с датчика не в вольтах, а в миливольтах, и больше не вычитать минимальное значения напряжения при отсутствии пыли, дабы увидеть если вообще какое-то изменение при “накуривании” сенсора. Заодно, руководствуясь графиком из Datasheet-а:

graphдобавил просто сообщение о качестве воздуха при разных значениях выдаваемого напряжения, вроде:

if (volt < 2500)
    return 0;
  else if (volt < 3600)
    return 1;
  else
    return 2;

и буду соответственно выводить на дисплей примерно так:

  if (bucket == 0)
    display.println("Perfect air");
  else if (bucket == 1)
    display.println("Avergae air");
  else if (bucket == 2)
    display.println("Light polution");
  else if (bucket == 3)
    display.println("Moderate pollution");
  else if (bucket == 4)
    display.println("Heavy pollution");
  else if (bucket == 5)
    display.println("Serious pollution");

20160227_213401Как будут интересные результаты – напишу финальный пост.

Управление жестами: Часть 1 – простые движения

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

Если вы едете в машине, то нажатие на кнопку вовремя движения (например, чтобы включить обдув лобового стекла) требует от вас оторвать глаза от дороги и найти эту кнопку… ну или нащупать по памяти. Гораздо проще произнести команду или махнуть рукой. И хотя распознавание речи тоже интересная тема, но тут я решил сконцентрироваться исключительно на устройствах распознавания жестов, с которыми мне удалось поработать – это Myo armband, Leap Motion и SparkFun RGB and Gesture Sensor.

20151215_123444 20151215_123832

Три разные “игрушки” , которые обладают разным функционалом, ценой, размерами и, видимо, областью применения.

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

одним из типичных представителей является ультразвуковой датчик определения расстояния, например hc-sr04.

20160227_221429Использовать его просто: согласно datasheet-у подается напряжение на триггер в течении 10 микросекунд, а затем считывается сигнал с ножки echo. Конечно уже есть готовые библиотеки для работы с этим датчиком, например NewPing, правда качество измерения крайне низкое если расстояние больше 10см.

20160301_134902Соответственно можно сделать простой скетч, который бы в случае обнаружения препятствия на расстоянии меньше, скажем, 6 сантиметров срабатывал как нажатие на кнопку. Вот пример реализации с ипользованием простенького i2c дисплея для отображения информации:

#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define Trig_pin 8
#define Echo_pin 7

#define press_range 6
#define measures 20

bool pressed = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(Trig_pin, OUTPUT);
  digitalWrite(Trig_pin, LOW);
  pinMode(Echo_pin, INPUT);
 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  pressed = false;
  display.display();
}

void loop() {
  unsigned int range = Ranging();


  if (range < press_range)
    pressed = !pressed;

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
 
  display.print("cm: ");
  display.println(range);
  if (pressed)
    display.println("pressed");
  else
    display.println("released");
 
  display.display();
  delay(300);
}

unsigned int Timing()
{
  digitalWrite(Trig_pin, HIGH);
  delayMicroseconds(10);
  digitalWrite(Trig_pin, LOW);
 
  return pulseIn(Echo_pin, HIGH);
}

unsigned int Ranging()
{
  unsigned int avgduration = 0;
  unsigned int maxdur = 0;
  unsigned int mindur = 0;
 
  for (int i = 0; i < measures; i++)
  {
    unsigned int etime = Timing();
    if (etime > maxdur)
      maxdur = etime;
    if (etime < mindur)
      mindur = etime;

    avgduration += etime;
    delay(1);
  }
 
  avgduration = (avgduration - (maxdur + mindur)) / (measures-2);
  return (avgduration /29 / 2);
}

Функция Timing() замеряет время которое потребовалось отражённому сигналу, чтобы вернуться. Функция Ranging() вызывает её 20 раз с задержкой 1 милисекунда, максимальное и минимальное значение отбрасываются, а оставшиеся усредняются. Затем просто проверяется, что если расстояние меньше заданного значения – 6 см, то произошло нажатие на кнопку. Работает это таким вот образом:

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

20160302_183300У них меньше дальность обнаружения, но есть цифровой выход, который говорит – близко объект или нет. Вот мой пример реализации:

#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define din1 4
#define ain1 A0

#define din2 2
#define ain2 A1

bool t1 = false;
bool t2 = false;
short drctn = 0;

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
 
  pinMode(din1,INPUT);
  pinMode(ain1,INPUT);

  pinMode(din2,INPUT);
  pinMode(ain2,INPUT);  
 
}

void loop() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);  

  unsigned int ad1=analogRead(ain1);
  unsigned int ad2=analogRead(ain2);

  int din1_val = digitalRead(din1);
  int din2_val = digitalRead(din2);

  if (t1 && !t2 && (din2_val == LOW))
    drctn = 1;
  else if (t2 && !t1 && (din1_val == LOW))
    drctn = -1;
  else if (!t1 && !t2)
    drctn = 0;
    
  if(din1_val==LOW)
  {
    display.print("1: Near | ");   
    t1 = true;
  }
  else
  {
    t1 = false;
    display.print("1: Far  | ");       
  }
 
  if(din2_val==LOW)
  {
    display.println("2: Near ");   
    t2 = true;
  }
  else
  {
    t2 = false;
    display.println("2: Far  ");       
  }
 
  display.print(ad1);
  display.print(" | ");
  display.println(ad2);

  if (drctn == -1)
    display.println("left");
  else if (drctn == 1)
    display.println("right");

 
  display.display();
  delay(100);
}

И вот как это работает:

Соответственно если добавить ещё один датчик расстояния, то можно расширить количество распознаваемых движений.

20160303_143009Например теперь можно распознать движения вверх и вниз. Вот как это работает:

Скетч отличается не сильно – идея та же самая. Если сначала сработал верхний дальномер а потом оба нижних, то движение вниз, если сначала оба нижних, а потом верхний, то движение вверх.

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

#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define din1 4
#define ain1 A0

#define din2 2
#define ain2 A1

#define din3 7
#define ain3 A2

bool t1 = false;
bool t2 = false;
bool t3 = false;
short drctn = 0;

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
 
  pinMode(din1,INPUT);
  pinMode(ain1,INPUT);

  pinMode(din2,INPUT);
  pinMode(ain2,INPUT);  

  pinMode(din3,INPUT);
  pinMode(ain3,INPUT);    
 
}

void loop() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);  

  unsigned int ad1=analogRead(ain1);
  unsigned int ad2=analogRead(ain2);
  unsigned int ad3=analogRead(ain3);

  int din1_val = digitalRead(din1);
  int din2_val = digitalRead(din2);
  int din3_val = digitalRead(din3);

  if (drctn == 0)
  {
    if (t1 && !t2 && (din2_val==LOW))
      drctn = 1;
    else if (t2 && !t1 && (din1_val==LOW))
      drctn = -1;
    else if (t1 && t2 && (din3_val==LOW))
      drctn = 2;
    else if (t3 && !t2 && !t2 && (din1_val==LOW) && (din2_val==LOW))
      drctn = -2;    
    else if (!t1 && !t2 && !t3 &&(din1_val==LOW) && (din2_val==LOW)&& (din3_val==LOW))
      drctn = -3;
  }
  if(din1_val==LOW)
  {
    display.print("1 Near ");   
    t1 = true;
  }
  else
  {
    t1 = false;
    display.print("1 Far ");       
  }
 
  if(din2_val==LOW)
  {
    display.print("2 Near ");   
    t2 = true;
  }
  else
  {
    t2 = false;
    display.print("2 Far ");       
  }

  if (din3_val==LOW)
  {
    display.println("3 Near");
    t3=true;
  }
  else
  {
    t3 = false;
    display.println("3 Far");
  }
 
  display.print(ad1);
  display.print(" ");
  display.print(ad2);
  display.print(" ");
  display.println(ad3);

  if (drctn == -1)
    display.println("left");
  else if (drctn == 1)
    display.println("right");
  else if (drctn == 2)
    display.println("up");
  else if (drctn == -2)
    display.println("down");
  else if (drctn == -3)
    display.println("push");
 
  display.display();

  if (!t1 && !t2 && !t3)
    drctn = 0;  
  delay(100);
}

и  пример того, как это работает

в следующем посте уже будут готовые решения вместо кустарных. Как вам идея управления жестами в целом?

Монитор качества воздуха своими руками: Часть 1 – Начало

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

Для начала я купил датчик пыли на основе sharp GP2Y1010AU0F прменяется для обнаружения PM2.5 частиц (менее 2.5 микрон) и сигаретного дыма. Принцип действия довольно простой: фототранзистор распознает свет, отражённый от частиц, который посылает инфракрасный светодиод.

20160130_130529Для подключения к Arduino не требуется ничего особенного: чёрный провод земля, красный 5 вольт, жёлтый на цифровой Pin 7, для управления (вкл/выкл) тем самым инфракрасным светодиодом, и синий на один из аналоговых пинов, например A0, для чтения показаний датчика.

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

#define DUST_ILED 7
#define DUST_PIN 0
#define NO_DUST_VOLT 0.9

void setup() {
  pinMode(DUST_ILED, OUTPUT);
  digitalWrite(DUST_ILED, LOW);
 
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(DUST_ILED, HIGH);
  delayMicroseconds(280);

  int outVolt = analogRead(DUST_PIN);

  digitalWrite(DUST_ILED, LOW);

  float calcVoltage = outVolt * 5.0 / 1024.0 - NO_DUST_VOLT;
  if (calcVoltage < 0) {
    calcVoltage = 0;
  }

  delay(1000);
}

Здесь мы делим значение, которое считали с датчика на 1024 – это максимальное значение, которое может считать Arduino Uno на аналоговых пинах и умножаем на 5 – напряжение, которое мы подали на датчик.

Согласно DataSheet-у типичное напряжение, которое показывает датчик при отсутствии пыли – это 0.9 вольт, так что просто вычтем это значение и будем считать, что наличие пыли начинается при напряжении > 0.9 вольт.

Второе, что нужно сделать – это отображать считанные значения. Простейший вариант – это напечатать в консоль, но когда ходишь по городу, то лучше иметь какой-нить маленький дисплей и я купил  0.96″ OLED дисплей с интерфейсом i2c, которому требуется 2 аналоговых пина (SDA на A4, а SCL на A5) плюс напряжение и земля.

20160130_174819У AdaFruit есть отличная, но “тяжёлая” библиотека для работы с подобными дисплеями. Прежде чем ею можно воспользоваться нужно поменять пару вещей в зависимости от модели дисплея. В моём случае это i2c адрес, который нужно выставить в 0x3C . Так же может понадобиться другая AdaFruit библиотека – AdaFruit GFX.

#include <Adafruit_SSD1306.h>

#define DUST_ILED 7
#define DUST_PIN 0
#define NO_DUST_VOLT 0.9

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

void setup() {
  pinMode(DUST_ILED, OUTPUT);
  digitalWrite(DUST_ILED, LOW);
  // put your setup code here, to run once:
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  display.display();
  delay(2000);

  // Clear the buffer.
  display.clearDisplay();
  display.display();
  

  
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(DUST_ILED, HIGH);
  delayMicroseconds(280);

  int outVolt = analogRead(DUST_PIN);

  digitalWrite(DUST_ILED, LOW);

  float calcVoltage = outVolt * 5.0 / 1024.0 - NO_DUST_VOLT;
  if (calcVoltage < 0) {
    calcVoltage = 0;
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Dust: ");
  display.println(calcVoltage);  
  display.display();
  delay(1000);
}

Теперь необходимо добавить датчики температуры и влажности для полноты информации. Например подойдёт DHT22 – это два датчика в одном.

20160130_130724У него 4 ножки, но одна (третья, согласно DataSheet-у) не используется, так что просто нужно подключить 5 вольт, землю и один из цифровых пинов, например 2й. Так же есть библиотека для работы с этим датчиком, так что считывание показаний можно легко добавить в предыдущий скетч:

#include <Adafruit_SSD1306.h>
#include <DHT.h>

#define DHT_TYPE DHT22
#define DHT_PIN 2

#define DUST_ILED 7
#define DUST_PIN 0
#define NO_DUST_VOLT 0.9

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

DHT dht(DHT_PIN,DHT_TYPE);

void setup() {
  pinMode(DUST_ILED, OUTPUT);
  digitalWrite(DUST_ILED, LOW);
  // put your setup code here, to run once:
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  display.display();
  delay(2000);

  // Clear the buffer.
  display.clearDisplay();
  display.display();
  

  
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(DUST_ILED, HIGH);
  delayMicroseconds(280);

  int outVolt = analogRead(DUST_PIN);

  digitalWrite(DUST_ILED, LOW);

  float calcVoltage = outVolt * 5.0 / 1024.0 - NO_DUST_VOLT;
  if (calcVoltage < 0) {
    calcVoltage = 0;
  }

  float h = dht.readHumidity();
  float t = dht.readTemperature();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("H: ");
  display.print(h);
  display.print(" T: ");
  display.println(t);  
  display.println("");
  display.setTextSize(2);
  display.print("Dust: ");
  display.println(calcVoltage);  
  display.display();
  delay(1000);
}

просто читаем влажность и температуру с помощью библиотечных функций dht.readHumidity() и dht.readTemperature() и выводим их на экран:

20160130_21055820160130_221420

Ещё нужен источник питания, такой, чтобы можно было легко носить “прибор” с собой. Например подойдут пальчиковые (АА) батарейки, которые можно вставить в батарейный отсек и приделать к ним разъём с клеммой для лёгкого способа подключения к Arduino

20160130_130601Сам Arduino засунуть в корпус и приклеить батарейный отсек с помощью 2х стороннего скотча:

20160130_130621 20160130_130631

Что скажите? Полезный девайс?

Управляемая RGB лампочка: Часть 1 – NeoPixel-и

Сейчас куда не глянь везде всё умное. Умные розетки, кофеварки, телевизоры и конечно же лампочки. Одной из первых таких ламп я увидел Philips HUE, и загорелся идеей сделать свою управляемую RGB лампочку. У такой лампочки масса очевидных преимуществ: задание цвета под настроение, автоматическое включение/выключение, светобудильник, плюс неочевидные, как например светомузыка. Сказано сделано – начинаем копать.

Первое, что нужно решить – это каким будет источник света. Сейчас в моде светодиоды – они компактны и потребляют мало электричества, к тому же у меня завалялось 15 NeoPixel-ей от Adafruit на основе ws2812b.

20160117_185334Это 3 светодиода в одном плюс управляющая электроника. Особенность в том, что управляются они по одному проводу (вместе с напругой и землёй – три). Грубо говоря по проводу с данными вы передаёте сигнал, представляющий массив значений цветов. А дальше первый NeoPixel “откусывает” от этого массива первый элемент, выставляет его себе и передаёт остаток дальше и так далее по цепочке.

20160117_193644Второе – это какую беспроводную технологию использовать. WiFi мне кажется более универсальной и лучше масштабируемой в отличии от Bluetooth – это позволяет добавлять огромное количество таких ламп и заодно даёт возможность управления ими с помощью любого устройства, находящегося в этой же сети (да и за её пределами). Да и радиус действия у них гораздо больше. К тому же у меня валялось 3 модуля на основе esp8266.

20160117_190110Третье – это на чем реализовать управляющую логику. В наличии был Arduino Uno к нему и решил подключить NeoPixel-и, следуя инструкции на сайте Adafruit.

20160117_195326Однако Arduino Uno слишком большой, чтобы он мог поместиться в корпус стандартной лампочки. В интернете мне попалось видео, как уменьшить свои Arduino Uno проекты используя ATTiny45/85. К тому же на instructables есть guide, как заставить ATTiny работать с NeoPixel-ями. Не долго думая я купил ATTiny45 и перенёс пример с полноценной Arduino Uno на эту мелочь.

20160117_201131 1 20160117_204324

С другой стороны esp8266 – это очень мощная штука при малых размерах. Помимо WiFi этот SoC имеет ещё и GPIO. Я взял ESP-01 у которого есть два GPIO. К тому же Arduino IDE поддерживает это семейство начиная с версии 1.6.4 и у Adafruit даже есть гайд по настройке. Единственная проблема – это то, как заливать туда свой софт. Я купил USB-Serail converter который имеет выходной сигнал на 3.3 вольта, так как 5 вольт убьет esp8266 и сделал две кнопки на макетной плате, так как для заливки нового софта требуется перевести один из пинов в Low и затем RESET-нуть esp8266, более подробно о том как заливать свои программы можно прочитать тут:

20160117_193458 20160117_193920 1

Пусть вас не смущает наличие Arduino Uno на картинке справа – его я использовал исключительно, чтобы получить 3.3 вольта и запитать esp8266, а также чтобы получить 5 вольт для NeoPixel-ей.

20160118_205216Стандартный пример от Adafruit заработал и я бросился писать простенькую программку, которая бы коннектилась к моей домашней WiFi сети, поднимала сокет и ждала число, которое бы определяло цвет светодиодов. В интернете я наткнулся на хороший пример того, как общаться с esp8266 и на его основе с небольшими изменениями, используя Adafruit API для управление светодиодами, я добился чего хотел.

Для проверки накропал простенький скрипт на Perl-е, который бы и отправлял цвет для лампы:

use strict;

use IO::Socket::INET;

my $sock = new IO::Socket::INET(PeerAddr => '192.168.1.35',
                                PeerPort => '6969',
                    Proto => 'tcp') || die "Can't bind $@\n";

$sock->send(shift."\n");

И сама прошивка

#include <Adafruit_NeoPixel.h>
#include <ESP8266WiFi.h>

#define NEOPIXEL_DATA_PIN 0
#define PIXELS_NUM 7

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXELS_NUM,
                                            NEOPIXEL_DATA_PIN,
                                           NEO_RGB + NEO_KHZ800);

const char* ssid = "mynetworkssid";
const char* password = "mynetpass";
WiFiServer server(6969);                                           

void setup() {
  Serial.begin(115200);
  strip.begin();
  strip.show();
 
  WiFi.begin(ssid, password);

  server.begin();
  while(WiFi.status() != WL_CONNECTED)
  {
    delay(500);
  }
}

void loop() {

  WiFiClient client = server.available();  
  if (client)
  {
    Serial.println("client connected.");
    while(client.connected())
    {
      if (client.available())
      {      
        String command;
        char c = client.read();
        while(c != '\n')
        {
          command += c;
          c = client.read();
        }

        if (command != 0)
        {
          char** tmp;
          char colorcommand[10];
          command.toCharArray(colorcommand, sizeof(colorcommand));
          
          uint32_t iColor = strtoul(colorcommand, tmp, 10);
           SetStripColors(iColor);
        }
      }
    }
    Serial.println("Client disconnected.");
    client.stop();
  }
}

void SetStripColors(uint32_t color)
{
  for (uint16_t i=0; i< PIXELS_NUM; i++)
  {
    strip.setPixelColor(i, color);
  }
  strip.show();
  delay(100);
}

Теперь дело за спецэфектами!

Цветомузыка в машину: Част 2 – Оцифровка

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

  • Первый и самый простой – это забить.
  • Второй – это использовать внешнюю звуковух вместе с Nexus 7
  • третий – это отказаться от использования планшета и собрать мультимедиа систему на базе одноплатного компьютера типа Raspberry Pi 2 или ODROID C1+. Вместе с HiFi Shield-ом (Для Raspberry Pi вот и Odroid C1 вот)

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

  • Первый, очевидный способ – это взять уже имеющийся EasyCap, по сколько он не только оцифровывает видео, но и аудио.
  • Второй – взять USB звуковуху специально для этой задачи.

20151103_220604

Решил попробовать оба. EasyCap на основе utv007 у меня уже был, а вот звуковуху пришлось купить, к счастью стоит она ~500р.

20151211_202757Lightshowpi – cофт, который я использовал в прошлый раз для управления светодиодной лентой на основе проигрываемой композиции, так же может работать и в режиме аудио захвата. Для этого нужно сделать конфиг, который укажет, что нужно работать именно с внешним аудио сигналом и какую звуковуху использовать для этих целей.

Для того, чтобы указать название звуковой карты нужно запустить скрипт (audio_in_cards.py), который идёт в комплекте – он то и выдаст список подключенных звуковых устройств. В моем случае правда он ничего не принтит и мне пришлось сделать небольшую модификацию в нём, чтобы он заработал:

cd lightshowpi/tools
vim audio_in_cards.py

надо на последнюю строчку добавить print

import alsaaudio as aa

if __name__ == "__main__":
    print aa.cards()

теперь всё как надо – запускаем:

pi@rpitestmusic ~/lightshowpi/tools $ sudo python audio_in_cards.py
[u'ALSA', u'usbtv']

Тут видно, что для EasyCap – это usbtv. Соответственно просто пропишем это в конфиг.

vim /home/pi/.lights.cfg

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

[hardware]
gpio_pins = 0,1,2

[lightshow]
mode = audio-in
audio_in_card = usbtv

Собственно, надо попробовать – как это работает. Запускаем скрипт в режиме захвата

sudo python py/synchronized_lights.py

Первое, чтоб бросается в глаза – это “шум”. Даже если нет никаких звуков лента всё равно моргает.

Теперь заменим EasyCap на купленную USB звуковуху. Честно взял некую рандомную. Вот dmesg если вдруг интересно:

cmediadmesgСнова запустив скрипт, который показывает название аудио устройств в системе, увидим, что имя, которое нужно поместить в конфиг – это просто Device.

pi@rpitestmusic ~/lightshowpi/tools $ sudo python audio_in_cards.py
[u'ALSA', u'Device']

Заменим usbtv на Device, используя любимый редактор vim /home/pi/.lights.cfg

[hardware]
gpio_pins = 0,1,2

[lightshow]
mode = audio-in
#audio_in_card = usbtv
audio_in_card = Device

И ребутнем Raspberry для профилактики возможных USB глитчей. После чего запустим скрипт syncronized_lights.py теперь уже с USB звуковой картой.

Заодно прикинул как это будет выглядеть если прилепить светодиодную ленту за телевизором:

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

Что скажите?

 

 

Коварные горничные – Анна Семинович, Дженифер Лопез, Лариса Долина и Сандра Балок вместе в одном сериале

Периодически пытаюсь смотреть какой-нить рандомный сериал, жанр которого мне далёк, а описание не вызывает у меня интерес. Зачем? Чтобы не пропустить годный сериал у которого неудачное описание, или вдруг мои вкусы изменились, а я об этом ещё не знаю…

Одним из таких недавних экспериментов стал сериал Отчаяные Домохозяйки Devious Maids / Коварные Горничные:

Devious.Maids.S01E01.1080p.rus.LostFilm.TV.mkv_snapshot_04.30_[2015.12.12_11.20.17]Сериал в общем-то говно, хотя на IMDB.com рейтинг у него 7.9 и уже снимается 4й сезон. Однако вот что меня привлекло в нём – это то, что в этом сериале снимаются актрисы, которые похожи на других актрис.

Судите сами. Вот например Brianna Brown ака Анна Семинович

annaseminovichannaseminovich_щкшп

Безусловно, когда ставишь фотографии рядом, то понятно, кто на самом деле Анна Семинович. И дело не только в _выдающихся_ “способностях” Анны, но и в принципе в том, что не существует двух одинаковых людей. Однако, когда смотришь сериал и рядом нет фотографии, чтобы сравнить, и, если бы Брианна, так сказать, “поднакачалась”, то в принципе сходу отличить было бы невозможно.

Ещё одно поразительное сходство, на этот раз по всем параметрам включая испано-мексиканский вид – это Dania Ramirez ака Дженнифер Лопез

jebifer_lopezjebifer_lopez_щкшп

Даже не знаю к чему придраться тут. Не смотря на разницу в 10 лет между ними, и всё таки разное происхождение: корни Дженифер уходят в Пуэрто Рико, а Даниа уроженка Доминиканской Республики, именно такой образ Дженнифер Лопез сидит в моем мозгу. Удивительное сходство по всем параметрам, включая фигуру.

Другая актриса, которая также похоже на Российскую звезду – это Judy Reyes ака Лариса Долина:

larisa_dolinalarisa_dolina_orig

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

И последнее сильное сходство в этом сериале – это Roselyn Sanchez ака Сандра Балок

sandra_bullockattends the 'Gravity' photocall during the 70th Venice International Film Festival at the Palazzo del Casino on August 28, 2013 in Venice, Italy.

Конечно, тот кто читает светские новости в курсе, что это не может быть Сандра из-за разности в возрасте, однако мне, как человеку, которому это чуждо, пришлось проверить, актёрский состав, для того, чтобы убедиться, что это не она. Ко всему прочему, специалисты по гриму и макияжу часто творят такие чудеса, что узнать знакомого актёра становиться невозможно. Так почему бы им не сделать наоборот – сделать какого-то непохожего человека копией известной личности.

Что скажите? Может в этом сериале актёры подбирались специально таким образом, чтобы они были похожи на известных людей? Или же это просто соответствие голливудскому стереотипу?

 

 

 

Цветомузыка в машину: Част 1 – прототип

Как я уже писал в этом посте при постройке клона Ambilight-а я купил “неправильную” светодиодную ленту, которую решил использовать для цветомузыки. И не просто цветомузыки, а цветомузыки в машине, заодно сделав из неё mood-light.

20151104_112108 20151107_115258 20151107_115336 20151107_115237

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

В качестве железа, опять таки Raspberry Pi 2 и EascyCap на базе utv007.

20151103_220658 20151103_220604

В качестве операционки всё тот-же Raspbian от 2015-05-05, который уже включает в себя драйвер для UTV007 скачал с официального сайта.

Быстрый поиск в интернете привел меня на сайт Lightshowpi.org, который я и решил попробовать, но сначала нужно подключить ленту, а для этого нам понадобятся:

  • Raspberry pi 2
  • хороший источник питания для Raspberry pi 2 (5 вольт)
  • RGB светодиодная лента на 12 вольт
  • 12 вольт источник питания для светодиодной ленты
  • EasyCap AV video grabber (да – это перебор, но так сложилось)
  • 3 низковольтовых NPN транзистора (например 2sd882p, вот datasheet на него)
  • 3 резистора на 510 Ом
  • 3 Резистора на 10 КОм
  • провода
  • макетная плата (опционально)

В качестве питания для Raspberry Pi 2 я пользуюсь SmartBuy-вским переходником 220в на 5в / 2 ампера

20151103_220456Подключение

Чтобы подключить ленту к Raspberry Pi 2, нам понадобятся 3 NPN транзистора (в моем случае NEC 2sd882p), так как на ленте три цвета: Красный, Зелёный и Синий, которыми мы и будем управлять. Схема подключения выглядит следующим образом:

LCD

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

Красный, зелёный и синий канал с помощью красного, зелёного и синего проводов соответственно подключаем к коллекторам транзисторов (согласно datasheet-у – средняя ножка), используя макетную плату:

20151129_195803

Эмиттеры транзисторов (ножка номер 3 – слева от базы) и землю Raspberry Pi (например pin 6) соединяем с общей землей, используя черные провода, а базы транзисторов через резистора 510 Ом подключаем к Raspberry P (pin 11,12,13):

20151129_201934 moodlightpinout

Также базы транзисторов соединяем с общей землей через резистора 10 КОм.

20151129_202334

И заключительный этап – соединяем общую землю с минусом источника питания, используя чёрный провод, а 12 вольт ленты с плюсом источника питания используя белый провод:

20151129_202605

в результате это должно выглядеть примерно вот так:

20151129_205320

Установка софта

После того как всё подключено, нам надо поставить софт. На сайте lightshowpi.org есть достойная инструкция.

Как обычно первым делом надо обновиться:

sudo apt-get update
sudo apt-get upgrade

Затем скачать и установить lightshowpi

git clone https://togiles@bitbucket.org/togiles/lightshowpi.git
cd lightshowpi
./install.sh

вот и всё перезагрузите ваш Raspberry Pi и запустите тест:

cd lightshowpi
sudo python py/hardware_controller.py --state=flash

Тест начнёт по очереди включать каналы. Если вы всё сделали правильно, то 0 канал должен включить красный, первый – зелёный, второй – синий, а остальные каналы не должны оказывать влияние на ленту:

test

Чтобы это исправить и оставить только 3 канала, а не 8, можно переопределить дефолтные значения. Просто создадим файл, в котором укажем, что мы хотим использовать только 3 pin-а на Raspberry Pi:

vim /home/pi/.lights.cfg

Для понимания того, что и как надо переопределить – откройте дефолтный конфиг. В случае с vim-ом это можно сделать открыв его в другом табе:

:tabnew /home/pi/lightshowpi/config/defaults.cfg

просто найдите строчку gpio_pins

gpio_pins_lightshowpi

Тут есть комментарий, что нужно указать номера pin-ов исходя из спецификации WiringPi, а не физической нумерации. К счастью на картинке, которую я уже показывал (а полную версию можно посмотреть тут), присутствует и нумерация в соответствии со спецификацией WiringPi:

moodlightpinout

Видно, что pin 11, который мы подключили к красному каналу соответсвует WiringPi = 0, pin 12 соответсвует WiringPi = 1 и pin 13 соответсвует WiringPi 2. То есть нам в нашем новом конфиге, который будет лежать в /home/pi/.lights.cfg просто нужно создать секцию hardware и  указать, что мы хотим использовать gpio_pins 0,1 и 2:

repin

Запустив тест ещё раз мы увидим, что используются только каналы с 0го по 2й:

3chanelsonly

Теперь осталось попробовать какой-нить mp3 файл:

Внимательный читатель вопросит, а зачем нам нужен был EasyCap. Об этом и другом – в следующей части.