Блог Дмитрия Сошникова

про технологии и человеческое счастье

Windows Remote Arduino–управляем настольной лампой прямо из универсального приложения Windows

Сейчас в Майкрософт мы проводим “неделю интернета вещей”, поэтому тема моего очередного поста – о подключении устройств к Windows. Я уже писал про различные сценарии подключение датчиков к облаку, но бывают сценарии, когда нам хочется просто подключить датчики или устройства к нашему компьютеру и удаленно ими управлять. Например, мы хотим сделать приложение, которое будет включать и выключать настольную лампу. В этих случаях самым простым решение будет использование Windows Remote Arduino – проекта, который был недавно объявлен в рамках партнерства с Arduino.

Что такое Windows Remote Arduino

Windows Remote Arduino – это библиотека WinRT, которая позволяет управлять цифровыми и аналоговыми каналами платы Arduino из Windows/Windows Phone приложения, с помощью привычных команд типа digitalRead/Write и analogRead/Write. При этом сама плата может быть подключена к компьютеру по USB или Bluetooth – важно, чтобы обеспечивался последовательный канал передачи данных. Помимо простых команд включения/выключения входов/выходов, в том или ином виде предусмотрена работа с шиной I2C и (в перспективе) сервоприводами.

image

Для работы необходимо, чтобы на плате Arduino была запущена специальная программа, поддерживающая выполнение команд по протоколу Firmata, а библиотека Windows Remote Arduino обменивается командами с платой, предоставляя программисту высокоуровневые функции управления.

Библиотеки Windows Remote Arduino доступны для Windows 8.1/Windows Phone 8.1 и для универсальных приложений Windows 10. Чтобы использовать их в своем проекте, в настоящее время проще всего клонировать Git-репозиторий проекта и добавить необходимые проекты в своё решение (пример я опишу ниже).

Пример – включатель лампочки

В моём примере я буду разрабатывать интеллектуальное приложение, включающее настольную лампу. Для этой цели я использую плату Arduino Uno и реле, способное коммутировать 220В. Реле подключается к какому-нибудь цифровому выходу (например, 7). Также для обнаружения присутствия человека будем использовать инфракрасный датчик присутствия, который включим в аналоговый вход A0. Для удобства коммутации мы используем Troyka Shiled от Амперки.

На приведенном ниже видео смотрите подробнее про hardware setup, а также весь проект в действиии.

 

Устанавливаем скетч Firmata на плату Arduino

Первым делом необходимо установить на плату Arduino стандартный скетч для выполнения команд Firmata. Такой скетч уже включен в стандартную поставку Arduino IDE – достаточно выбрать в меню File –> Examples –> Firmata –> Standard Firmata. Открывшийся при этом скетч необходимо загрузить в плату обычным образом.

image

На этом этапе полезно будет убедиться, что все аппаратное обеспечение настроено правильно. Для этого можно использовать специальную программу firmata_test.exe (или любую из программ, описанных здесь) – вы должны быть в состоянии управлять лампочкой, переключая состояние цифрового выхода 7, а также на входе A0 вы должны получать значение 0, если движения вокруг сенсора нет, и большое положительное значение (около 600 и более) в противном случае.

image image

Готовим проект с Windows Remote Ardunio

Чтобы использовать Windows Remote Arduino в своём проекте, необходимо подключить соответствующие библиотеки. На текущий момент технология достаточно молодая, и библиотеки существуют в виде исходных текстов. Мы надеемся, что со временем появятся пакеты NuGet, сейчас же процесс включения библиотек выглядит следующим образом:

1. Создадим новый проект – в нашем случае это будет универсальное приложение Windows 10

2. Клонируйте GitHub-репозиторий проекта Windows Remote Arduino в какую-нибудь локальную папку:

git clone https://github.com/ms-iot/remote-wiring/

ВАЖНО: в репозитории имеются несколько версий библиотеки. На момент написания статьи последняя ветка master содержала много ошибок при работе с аналоговыми и цифровыми входами, поэтому я использовать наиболее стабильную ветку revert-18-develop. Очень надеюсь, что в скором времени выйдет еще более стабильная версия, и клонировать можно будет как показано выше, без указания ветки.

3. В получившемся дереве проектов есть папки Microsoft.Maker.Win10 и Microsoft.Maker.Win8_1. Мы будем использовать вариант для Windows 10, но проект поддерживает и универсальные приложения Windows 8.1

4. В папке Microsoft.Maker.Win10 есть три проекта: Microsoft.Maker.Firmata, Microsoft.Maker.Serial и Microsoft.Maker.RemoteWiring. Эти три проекта нужно добавить в созданный нами проект (Add Existing Project)

5. В результате получится следующее дерево проектов:

image image

6. Чтобы проекты компилировались в правильном порядке, необходимо установить правильные зависимости проектов. Нажмите правой кнопкой на наш проект, выберите “Зависимости сборки –> Зависимости проектов”, и установите галочки напротив всех трех добавленных проектов. Остальные зависимости должны быть уже установлены, но вы можете их проверить: проект Firmata зависит от проекта Serial, проект RemoteWiring – от проектов Firmata и Serial. Соответственно, на вкладке “Порядок сборки” проекты должны собираться в таком порядке: Serial, Firmata, RemoteWiring и наше приложение.

7. В нашем основном проекте правой кнопкой нажмите на References и добавьте расширение Microsoft Visual C++ AppLocal Runtime Package for Windows UAP. Там же в пункте “Общие проекты” выберите все три добавленных проекта Windows Remote Arduino.

image

8. ВАЖНО: Чтобы наше приложение могло использовать возможности работы с последовательным портом, необходимо в манифест приложения (файл Package.appxmanifest) в раздел <Capabilities> добавить следующий код:

<DeviceCapability Name="serialcommunication">
  <Device Id="any">
    <Function Type="name:serialPort"/>
  </Device>
</DeviceCapability>

9. Мы готовы к созданию нашего приложения, которое будет использовать библиотеки Windows Remote Arduino! Чтобы убедиться, что всё работает правильно, попробуйте выполнить сборку получившегося приложения.

Создаем приложение с Windows Remote Arduino

Наше приложение будет иметь три кнопки: для включения лампочки, для выключения, и для авто-режима, в котором лампочка будет управляться датчиком присутствия. Для начала добавим на главную страницу приложения MainPage.xaml эти три кнопки, установив их в неактивное состояние:

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
    <Button x:Name="on" IsEnabled="False" Content="ON" FontSize="30" Width="150" Height="150" Click="on_Click"></Button>
    <Button x:Name="off" IsEnabled="False" Content="OFF" FontSize="30" Width="150" Height="150" Click="off_Click"></Button>
    <Button x:Name="auto" IsEnabled="False" Content="AUTO" FontSize="30" Width="150" Height="150" Click="auto_Click" ></Button>
    <TextBlock x:Name="txt"/>
    <ListBox x:Name="lst"/>
</StackPanel>

Этот код добавляется внутрь того контейнера Grid, который уже по умолчанию есть у страницы. Также для каждой кнопки создадим функцию-обработчик на C# (кликнув дважды на каждую кнопку, или через окно свойств Visual Studio).

Для начала инициализируем объект Remote Arduino. Для этого в классе окна в файле MainPage.xaml.cs опишем две переменные

UsbSerial usbcomm;
RemoteDevice arduino;

Для подключение к Arduino опишем функцию connect(), которую затем вызовем из конструктора MainPage():

private async void connect()
{
    var dev = await UsbSerial.listAvailableDevicesAsync();
    usbcomm = new UsbSerial(dev[0]);
    arduino = new RemoteDevice(usbcomm);
    usbcomm.ConnectionEstablished += Comm_ConnectionEstablished;
    usbcomm.begin(57600, SerialConfig.SERIAL_8N1);
}

Здесь мы сначала определяем список доступных портов, куда может быть подключен Arduino, затем создаем последовательное соединение UsbSerial с этим портом, а затем поверх этого – объект RemoteDevice, который будет представлять собой виртуальный Arduino. После этого мы вызываем функцию begin, передавая параметры последовательного соединения.

ВАЖНО: Скорость последовательного канала, используемая протоколом Firmatа, задается в скетче StandardFirmata. По умолчанию она равна 57600, поэтому мы выбираем именно эту скорость в нашем приложении. Если скорости не будут совпадать, то соединение не будет работать.

При установлении соединения с платой, будет вызвана функция Comm_ConnectionEstablished, которую мы опишем следующим образом:

private void Comm_ConnectionEstablished()
{
    Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,new Windows.UI.Core.DispatchedHandler(() =>
    {
        arduino.pinMode(14, PinMode.ANALOG);
        arduino.pinMode(relay_pin, PinMode.OUTPUT);
        dt = new DispatcherTimer() { Interval = new TimeSpan(500) };
        dt.Tick += loop;
        dt.Start();
        on.IsEnabled = true;
        off.IsEnabled = true;
        auto.IsEnabled = true;
    }));
}

Основной код функции обернут в вызов диспетчера, который запускает его в потоке UI – это важно. Далее мы устанавливаем режимы основных используемых пинов Arduino, создаем таймер, который будет вызывать каждые пол-секунды функцию loop(), а также делаем кнопки видимыми.

Интересный момент – установка порта 14 в аналоговый режим. Дело в том, что аналоговые входы в Arduino нумеруются после цифровых, и входу A0 соответствует номер 14. Режим необходимо установить именно ANALOG, а не INPUT, который означает цифровой ввод.

Теперь для включения/выключения лампочки достаточно описать функции-обработчики событий кнопок следующим образом:

private void on_Click(object sender, RoutedEventArgs e)
{
    auto_mode = false;
    arduino.digitalWrite(relay_pin, PinState.HIGH);
}

Функция off_Click делается по аналогии. Обратите внимание, что для работы с пинами удалённой платы Arduino используются привычные команды типа digitalRead/digitalWrite.

Переменная auto_mode – это переменная типа bool, которую нужно описать в нашем классе. Она нужна для того, чтобы обрабатывать автоматический режим. Кнопка AUTO будет устанавливать эту переменную в true:

private void auto_Click(object sender, RoutedEventArgs e)
{
    auto_mode = true;
}

Теперь дело осталось за малым – реализовать функцию loop, которая будет переключать лампу в зависимости от наличия сигнала с датчика присутствия. Делать это надо только в том случае, если auto_mode установлен:

private void loop(object sender, object e)
{
    if (auto_mode)
    {
        arduino.pinMode(14, PinMode.ANALOG);
        var on = arduino.analogRead(0) > 512;
        arduino.digitalWrite(relay_pin, on ? PinState.HIGH : PinState.LOW);
    }
}

ВАЖНО: Для более надежной работы прямо перед чтением порта лучше еще раз установить его режим в аналоговый. Так быть не должно, но на практике это улучшает стабильность. Также обратите внимание, что мы используем analogRead(0), хотя строчкой ранее указывали номер порта 14. В analogRead передается номер порта от 0 до 5, при установке режима порта надо прибавить к этим номерам 14.

Как подключить Arduino по Bluetooth и управлять со смартфона

В нашем случае мы написали универсальное приложение, которое можем разместить на Windows Phone 10. Однако это бесполезно, поскольку подключить плату Arduino по USB к смартфону невозможно. Однако если мы будем использовать Bluetooth вместо USB-соединения, подключив к Arduino bluetooth-плату, то мы сможем этим же приложением управлять нашей конструкцией со смартфона. В этом случае в манифест приложения необходимо добавить следующие строчки для разрешения коммуникации по Bluetooth:

<DeviceCapability Name="bluetooth.rfcomm">
  <Device Id="any">
    <Function Type="name:serialPort"/>
  </Device>
</DeviceCapability>

Мы не будем сейчас рассматривать использование bluetooth – это тема для отдельной статьи. Однако заметим, что с точки зрения программирования разницы почти нет – надо использовать объект BluetoothSerial вместо UsbSerial, а все остальные конструкции остаются без изменений.

Где взять исходный код

image

Исходный код моего проекта по традиции доступен на GitHub:

https://github.com/evangelism/RemoteArduinoLamp/tree/v1.0-serial

Пожалуйста, берите его, экспериментируйте, если найдете ошибки – делайте pull requests.

Выводы

Windows Remote Arduino – достаточно молодая и сырая технология, но уже сейчас она может упростить решения ряда задач, в которых необходимо напрямую управлять входами/выходами платы Arduino, подключенной к компьютеру. Конечно, всё тоже самое можно запрограммировать вручную, написав свой скетч и используя последовательный канал для взаимодействия с ним, но почему бы не использовать уже готовые наработки и сложившиеся стандарты (Firmata), чтобы не изобретать велосипеды.

Я надеюсь, вы будете использовать Windows Remote Arduino в своих проектах, и если вы сделаете что-то интересное – мне будет приятно об этом узнать! Пишите в комментариях, в твиттере или вконтакте!

3 comments

Подключение Arduino к Raspberry Pi

Как я уже писал ранее, во многих сценариях интернета вещей бывает полезно иметь один достаточно мощный встраиваемый компьютер (в роли которого может выступать Raspberry Pi), который может связываться с множеством расположенных в разных местах сенсоров, управляемых простыми микроконтроллерами семейства Arduino. При этом можности Raspberry Pi хватает, чтобы передавать данные по защищенным каналам HTTPS в облако, а также чтобы осуществлять взаимодействие с пользователем посредством развитого интерфейса (например, при работе под управлением Windows 10).

Для соединения Arduino с Raspberry Pi существует несколько сценариев подключения:

    • Использование явного последовательного канала передачи данных. При этом возникают сложности, связанные с разностью уровней питания: Raspberry Pi работает на напряжении 3.3В, в то время как Arduino использует 5 вольт. При этом для обеспечения безопасного соединения рекомендуется использовать специальные преобразователи уровня.
    • Использование последовательной шины I2C, что позволяет подключать к одной Raspberry Pi до 128 устройств Arduino в режиме slave, при этом такое подключение также не требует преобразователей уровня.
    • Подключение по USB является пожалуй самым простым способом, поскольку для этого достаточно всего лишь воткнуть Arduino через стандартный кабель в USB-разъем Raspberry Pi. Именно этот способ мы и рассмотрим.

В качестве примера рассмотрим простейший датчик температуры и давления BMP-180, подключенный к Arduino Uno по стандартной схеме. После этого контроллер Arduino включается в USB-разъем Raspberry Pi, а сам Raspberry Pi затем подключается обычным образом к питанию, монитору и т.д.

WP_20150427_18_39_55_Pro

При таком подключении общение Arduino и Raspberry происходит по последовательному порту. Предварительно (до подключения) на Arduino необходимо залить требуемый скетч – в нашем случае это простая программа, считывающая значение давления и температуры с датчика и печатающая их в виде текста в последовательный канал (температура предваряется символом Т, а давление – P):


#include &lt;Wire.h&gt;
#include &lt;BMP180.h&gt;

BMP180 barometer;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  barometer = BMP180();
  if(barometer.EnsureConnected())
  {
    barometer.SoftReset();
    barometer.Initialize();
  }
  else
  {
    Serial.println(&quot;E&quot;);
  }
}

void loop()
{
  if(barometer.IsConnected)
  {
    long pres = barometer.GetPressure();
    float temp = barometer.GetTemperature();
    Serial.print(&quot;P&quot;); Serial.println(pres);
    Serial.print(&quot;T&quot;); Serial.println(temp);
    delay(1000);
  }
}

Проверим работоспособность скетча в Arduino IDE, открыв монитор последовательного порта – мы должны увидеть появляющиеся значения температуры и давления. Обратите внимание на скорость – в программе задана скорость в 9600 бод, такие же установки должны быть и у монитора последовательного порта.

Теперь загрузим Raspberry Pi – в моем примере я использую Pidora в качестве базовой операционной системы и классическую модель Rapsberry Pi, хотя с таким же успехом можно использовать Raspberry Pi 2 и Windows 10.

Первым делом нужно определить, какой последовательный порт будет отвечать за общение с Arduino-контроллером. Проще всего это сделать следующим образом: при выключенной плате Arduino смотрим все доступные последовательные терминалы (ls /dev/tty*), после чего включаем плату в USB-порт, и через некоторое время снова смотрим список терминалов. То устройство, которое появилось в списке, и будет требуемым портом. В моём случае это был /dev/ttyUSB0, но в зависимости от номера порта, используемого дистрибутива системы и других факторов это имя может сильно отличаться.

2015-04-27-190009_1920x1200_scrot

Теперь мы можем использовать любые средства общения с последовательным портом для того, чтобы принять значения от датчика, передаваемые Arduino. Чаще всего удобным оказывается использовать Python и библиотеку serial. Например, следующий простой скрипт, набранный прямо в REPL, будет отображать на экране все данные, приходящие в последовательный порт:

import serial
ser = serial.Serial(&quot;/dev/ttyUSB0&quot;,9600)
while 1:
   ser.readline()

Ниже показано, как этот скрипт выполняется в окне терминала на Raspberry Pi:

2015-04-27-185823_1920x1200_scrot

После этого получения данных в требуемом виде с последующей отправкой их в облако или сохранением в локальной базе данных является делом техники. Об этом я поговорю в следующих выпусках своей колонки про интернет вещей.

1 comment

От погодной станции к взрослому интернету вещей. Проект Connect the Dots

Я уже раньше писал про создания простейшей погодной станции на NetDuino. У рассмотренного решения есть ряд недостатков:

  • Используется достаточно редкий контроллер NetDuino 2 Plus – было бы здорово перейти с него на более классический и недорогой Arduino
  • Передача данных в сеть идет по незащищенному каналу связи HTTP – в реальных задачах разумнее использовать HTTPS, чтобы а значит для отправки данных необходим более мощный процессор, чем в Arduino
  • Предложенный подход с веб-сервисом не всегда способен принять большой поток данных, поэтому если мы хотим поддерживать множество аналогичных погодных станций – необходимо использовать специальные облачные механизмы для интернета вещей, такие как концентраторы событий (Event Hub).

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

Аппаратная сторона

Итак, для отправки HTTPS-запросов и для работы с продвинутыми сервисами Azure нам необходим более мощный процессор, чем в Arduino – при этом Arduino по-прежнему остаётся стандартом де-факто для подключения различных датчиков. Поэтому обычно используют в том или ином виде комбинацию Arduino с более мощным микрокомпьютером, обычно работающим под управлением какой-то операционной системы:

  • Связка Raspberry Pi + Arduino. Raspberry Pi представляет собой недорогой одноплатный контроллер стоимостью около $35, на котором могут работать как разные версии UNIX, так и Windows 10. В случае простых датчиков – их можно подключить прямо к Raspberry Pi, но обычно используют Arduino, которое может быть связано с Raspberry Pi по последовательному каналу либо через USB (самый простой способ), либо напрямую или по интерфейсу I2C. Преимуществом Raspberry Pi является то, что можно использовать достаточно мощную операционную систему и производить на плате не только передачу данных, но и осмысленную пред-обработку и принятие решений.
  • Arduino Yun представляет собой одну плату, на которой по сути совмещена функциональность классического Arduino Uno и микрокомпьютера под управлением специальной версии Linux – OpenWrt. С точки зрения программирования такая связка очень похожа на рассмотренный выше вариант с Raspberry Pi, но при этом мы имеем одну плату (правда, с чуть менее функциональной ОС).
  • Intel Gallileo или Edison – это компактные платы на основе процессоров x86, которые аппаратно совместимы с Arduino, при этом работают под управлением полноценной ОС типа Unix (или даже Windows). Можно работать со всеми аппаратными возможностями этих плат непосредственно из уровня ОС (например, используя Python и библиотеку Wiring x86 – пример такого скрипта смотрите тут, при этом такой же скрипт может отправлять данные в облако), либо с помощью эмулятора Arduino – в этом случае аппаратная часть программируется стандартным способом как Arduino Sketch в Arduino IDE, и затем связывается с базовой ОС через вызов system для отправки данных (пример смотрите тут).
  • Конечно, можно еще использовать полноценный персональный компьютер с подключенным Arduino, но такой способ мы не будем рассматривать ввиду его простоты и экономической неэффективности.

Программная часть

Для отправки потоковых данных с датчиков в облако рекомендуется использовать технологию концентраторов событий. Если вы используете в качестве базового микрокомпьютера Raspberry Pi, Arduino Yun или Intel Galileo, то удобнее всего будет разрабатывать на Python. Для этого установите свежую версию Azure SDK for Python, в котором есть API для работы с Event Hub. Более подробный пример работы (с использованием более старого API) приведен тут, документация по функциям работы с Event Hub – тут, а я постараюсь в ближайшее время также описать этот процесс на русском языке.

Проект Connect-the-Dots

Проект Connect-the-Dots – это проект Microsoft Open Technologies с открытым исходным кодом, который показывает разные сценарии использования сенсоров для сбора данных в облаке с использованием Event Hub. Он по сути дела представляет собой реализацию тех принципов, о которых я написал выше – использование достаточно производительных контроллеров для отправки потоковых данных в Azure Event Hub.

image

В качестве сценариев поддерживается прямая отсылка данных в облако (с Intel Galileo или плат на основе .NET MicroFramework), или же использование шлюза на базе Raspberry Pi и конечных устройств на Arduino Uno, а также возможность использовать Windows Phone как прямой источник данных (освещенность, акселерометр и т.д.).

Проект Connect-the-Dots хорошо использовать как отправную точку для своих масштабных проектов, связанных с интернетом вещей. Более скромные проекты, возможно, имеет смысл делать с меньшим размахом – про это я буду писать в своих следующих заметках.

7 comments