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

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

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

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

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

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

3 comments

Как Microsoft дружит с Arduino и другими на почве IoT

Пару месяцев назад в рамках конференции Build было объявлено о партнерстве Microsoft с платформой Arduino, а Windows 10 была названа первой Arduino-сертифицированной операционной системой. Исходные анонсы вы можете прочитать на сайте Arduino и в официальном блоге Windows. Давайте разберемся, что же стоит за этими объявлениями.

image

Самое главное, что следует из этого объявления – Microsoft понимает важность платформы Arduino и будет предпринимать усилия, чтобы соответствующие устройства хорошо взаимодействовали с устройствами на Windows 10. Представьте себе мир, в котором внешние электронные устройства на базе Arduino являются продолжением аппаратного обеспечения компьютера, работающего под управлением Windows 10, и доступны из стандартных универсальных приложений с помощью соответствующих расширений. Это позволит оптимальным образом сочетать вычислительную мощность традиционных компьютеров и облака с потенциалом микроконтроллеров по управлению устройствами, создавая целостные решения в области интернета вещей.

В рамках текущих анонсов было объявлено о доступности двух технологий:

  • Windows Remote Arduino – это технология, которая позволяет управлять платой Arduino, подключенной по USB или Bluetooth, из универсального приложения, как если бы её порты ввода-вывода были доступны локально. Разработчику универсального приложения становятся доступны основные команды по работе с аналоговыми и цифровыми портами, что позволяет напрямую работать с рядом датчиков. Для взаимодействия Arduino с компьютером используется протокол Firmata, а на плате запускается специальный Firmata Sketch, выполняющий приходящие от удаленного компьютера команды. Проект доступен для Windows 8.1 и Windows 10 в виде исходных текстов на GitHub.
  • Windows Virtual Shield for Arduino позволяет использовать смартфон под управлением Windows Phone 10 в качестве виртуальной платы расширения для Arduino. При этом смартфон может использоваться как текстовый экран, как гироскоп/акселерометр/GPS, в качестве распознавателя речи и т.д. Вы получаете простой доступ ко всем этим возможностям прямо из своего Arduino Sketch. В качестве примера можно посмотреть на проект Picture the Weather.

image

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

В новом мире многие инновации делаются энтузиастами, которые любят собирать что-то своими руками – в английском языке для этого есть прекрасное слово maker. Понимая важность такого сообщества для будущих инноваций в IoT, Microsoft также объявила о партнерстве с популярным порталом Hackster.IO, на котором теперь будут представлены многие официальные примеры разработок для Windows IoT.

image

Если же говорить про промышленный интернет вещей, то здесь важной задачей является построение инфраструктуры для взаимодействия сети устройств между собой и с клиентами. Одной из таких платформ межмашинного взаимодействия является DeviceHive от компании DataArt. В результате партнерства компании с Microsoft теперь можно легко разворачивать DeviceHive в облаке прямо из магазина Azure Marketplace, что существенно упрощает создания облачных решений для интернета вещей.

image

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

1 comment