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

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

You are currently browsing the Проекты category.

Магия треугольника Серпинского в функциональном стиле

Сегодня мы поговорим про замечательную геометрическую фигуру: треугольник Серпинского. Это фрактальная самоподобная структура, которая однако очень проста в построении.

image

Алгоритм построения треугольника таков:

  • Задаем координаты трех вершин-аттракторов (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:

sierpinski ((0,0),(300,600),(600,0)) |> Seq.take 5000 |> Chart.FastPoint

Вот какой получился результат:

image

Весь исходный код можно найти здесь: http://fssnip.net/ta.

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

Posted Ноябрь 3rd, 2015.

Add a comment

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 в своих проектах, и если вы сделаете что-то интересное – мне будет приятно об этом узнать! Пишите в комментариях, в твиттере или вконтакте!

Posted Июль 11th, 2015.

3 comments

От погодной станции к взрослому интернету вещей. Проект 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 хорошо использовать как отправную точку для своих масштабных проектов, связанных с интернетом вещей. Более скромные проекты, возможно, имеет смысл делать с меньшим размахом – про это я буду писать в своих следующих заметках.

Posted Апрель 28th, 2015.

7 comments