Сегодня мы поговорим про замечательную геометрическую фигуру: треугольник Серпинского. Это фрактальная самоподобная структура, которая однако очень проста в построении.
Алгоритм построения треугольника таков:
Задаем координаты трех вершин-аттракторов (x1,y1), (x2,y2) и (x3,y3)
Выбираем некоторую точку (x,y) внутри треугольника
Повторяем много раз:
Ставим точку с координатами (x,y)
Выбираем случайным образом одну из вершин (xi,yi)
Вычисляем координаты новой точки по формуле ((x+xi)/2,(y+yi)/2)
Такой алгоритм легко реализовать на любом языке программирования, однако его реализация на функциональных языках имеет ряд интересных моментов. В частности, для вычисления координат всех точек треугольника мы используем концепцию корекурсии.
В соответствии с этим, мы реализуем функцию sierpinski, которая будет возвращать бесконечную последовательность координат точек треугольника:
let sierpinski (p1,p2,p3) =
let rec sierpinski' pt =
seq {
let p = pick [p1;p2;p3]
let pt' = mid pt p
yield pt'
yield! sierpinski' pt'
}
sierpinski' (mid3 p1 p2 p3)
В этом определении мы используем вспомогательную вложенную рекурсивную функцию sierpinski’, которая в качестве аргумента передает координаты текущей точки pt. Координаты вершин p1,p2,p3 в данном случае являются внешними по отношению к этой функции. Далее мы выбираем одну из вершин случайным образом, вычисляем координаты очередной точки, “возвращаем” (с помощью yield) эти координаты, и затем рекурсивно возвращаем бесконечный остаток списка, который получается из рекурсивного вызова. Затем чтобы сформировать результат мы вызываем sierpinsky’, передавая ему в качестве начальной точки среднюю точку, вычисленную из координат вершин.
Для вычисления средних точек мы определим следуюшие вспомогательные функции:
let mid (x1,y1) (x2,y2) = (x1+x2)/2,(y1+y2)/2
let mid3 (x1,y1) (x2,y2) (x3,y3) = (x1+x2+x3)/3,(y1+y2+y3)/2
Для выбора вершины случайным образом мы используем немного нефукнциональный подход, который зато позволяет быстро получить требуемую функциональность:
let Rnd = new Random()
let pick (L:'t list) = L.[Rnd.Next(0,Seq.length L)]
В завершение остаётся лишь построить полученный треугольник. Для этого можем использовать стандартную библиотеку FSharp.Charting:
В качестве самостоятельного упражнения, попробуйте в качестве эксперимента модифицировать функцию sieprinski, чтобы она могла принимать произвольное число вершин. И посмотрите, будет ли сохраняться фрактальное свойство для квадратов, шестиугольников и т.д. Буду рад видеть результаты ваших экспериментов в комментариях!
Windows Remote Arduino – это библиотека WinRT, которая позволяет управлять цифровыми и аналоговыми каналами платы Arduino из Windows/Windows Phone приложения, с помощью привычных команд типа digitalRead/Write и analogRead/Write. При этом сама плата может быть подключена к компьютеру по USB или Bluetooth – важно, чтобы обеспечивался последовательный канал передачи данных. Помимо простых команд включения/выключения входов/выходов, в том или ином виде предусмотрена работа с шиной I2C и (в перспективе) сервоприводами.
Для работы необходимо, чтобы на плате 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. Открывшийся при этом скетч необходимо загрузить в плату обычным образом.
На этом этапе полезно будет убедиться, что все аппаратное обеспечение настроено правильно. Для этого можно использовать специальную программу firmata_test.exe (или любую из программ, описанных здесь) – вы должны быть в состоянии управлять лампочкой, переключая состояние цифрового выхода 7, а также на входе A0 вы должны получать значение 0, если движения вокруг сенсора нет, и большое положительное значение (около 600 и более) в противном случае.
Готовим проект с Windows Remote Ardunio
Чтобы использовать Windows Remote Arduino в своём проекте, необходимо подключить соответствующие библиотеки. На текущий момент технология достаточно молодая, и библиотеки существуют в виде исходных текстов. Мы надеемся, что со временем появятся пакеты NuGet, сейчас же процесс включения библиотек выглядит следующим образом:
1. Создадим новый проект – в нашем случае это будет универсальное приложение Windows 10
ВАЖНО: в репозитории имеются несколько версий библиотеки. На момент написания статьи последняя ветка 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. В результате получится следующее дерево проектов:
6. Чтобы проекты компилировались в правильном порядке, необходимо установить правильные зависимости проектов. Нажмите правой кнопкой на наш проект, выберите “Зависимости сборки –> Зависимости проектов”, и установите галочки напротив всех трех добавленных проектов. Остальные зависимости должны быть уже установлены, но вы можете их проверить: проект Firmata зависит от проекта Serial, проект RemoteWiring – от проектов Firmata и Serial. Соответственно, на вкладке “Порядок сборки” проекты должны собираться в таком порядке: Serial, Firmata, RemoteWiring и наше приложение.
7. В нашем основном проекте правой кнопкой нажмите на References и добавьте расширение Microsoft Visual C++ AppLocal Runtime Package for Windows UAP. Там же в пункте “Общие проекты” выберите все три добавленных проекта Windows Remote Arduino.
8. ВАЖНО: Чтобы наше приложение могло использовать возможности работы с последовательным портом, необходимо в манифест приложения (файл Package.appxmanifest) в раздел <Capabilities> добавить следующий код:
9. Мы готовы к созданию нашего приложения, которое будет использовать библиотеки Windows Remote Arduino! Чтобы убедиться, что всё работает правильно, попробуйте выполнить сборку получившегося приложения.
Создаем приложение с Windows Remote Arduino
Наше приложение будет иметь три кнопки: для включения лампочки, для выключения, и для авто-режима, в котором лампочка будет управляться датчиком присутствия. Для начала добавим на главную страницу приложения MainPage.xaml эти три кнопки, установив их в неактивное состояние:
Этот код добавляется внутрь того контейнера 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, которую мы опишем следующим образом:
Основной код функции обернут в вызов диспетчера, который запускает его в потоке UI – это важно. Далее мы устанавливаем режимы основных используемых пинов Arduino, создаем таймер, который будет вызывать каждые пол-секунды функцию loop(), а также делаем кнопки видимыми.
Интересный момент – установка порта 14 в аналоговый режим. Дело в том, что аналоговые входы в Arduino нумеруются после цифровых, и входу A0 соответствует номер 14. Режим необходимо установить именно ANALOG, а не INPUT, который означает цифровой ввод.
Теперь для включения/выключения лампочки достаточно описать функции-обработчики событий кнопок следующим образом:
Функция off_Click делается по аналогии. Обратите внимание, что для работы с пинами удалённой платы Arduino используются привычные команды типа digitalRead/digitalWrite.
Переменная auto_mode – это переменная типа bool, которую нужно описать в нашем классе. Она нужна для того, чтобы обрабатывать автоматический режим. Кнопка AUTO будет устанавливать эту переменную в 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:
Мы не будем сейчас рассматривать использование bluetooth – это тема для отдельной статьи. Однако заметим, что с точки зрения программирования разницы почти нет – надо использовать объект BluetoothSerial вместо UsbSerial, а все остальные конструкции остаются без изменений.
Где взять исходный код
Исходный код моего проекта по традиции доступен на GitHub:
Пожалуйста, берите его, экспериментируйте, если найдете ошибки – делайте pull requests.
Выводы
Windows Remote Arduino – достаточно молодая и сырая технология, но уже сейчас она может упростить решения ряда задач, в которых необходимо напрямую управлять входами/выходами платы Arduino, подключенной к компьютеру. Конечно, всё тоже самое можно запрограммировать вручную, написав свой скетч и используя последовательный канал для взаимодействия с ним, но почему бы не использовать уже готовые наработки и сложившиеся стандарты (Firmata), чтобы не изобретать велосипеды.
Я надеюсь, вы будете использовать Windows Remote Arduino в своих проектах, и если вы сделаете что-то интересное – мне будет приятно об этом узнать! Пишите в комментариях, в твиттере или вконтакте!
Используется достаточно редкий контроллер 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.
В качестве сценариев поддерживается прямая отсылка данных в облако (с Intel Galileo или плат на основе .NET MicroFramework), или же использование шлюза на базе Raspberry Pi и конечных устройств на Arduino Uno, а также возможность использовать Windows Phone как прямой источник данных (освещенность, акселерометр и т.д.).
Проект Connect-the-Dots хорошо использовать как отправную точку для своих масштабных проектов, связанных с интернетом вещей. Более скромные проекты, возможно, имеет смысл делать с меньшим размахом – про это я буду писать в своих следующих заметках.