Статьи

Изучите IoT, создавая сенсорный проект с Raspberry Pi и сенсорами

Узнайте, как создать сенсорный проект в этом гостевом посте от Питера Вара, эксперта по IoT.

Разработка датчика разбита на шесть этапов. Вот простой обзор:

  1. Во-первых, вы настроите базовую структуру консольного приложения.
  2. Затем вы сконфигурируете аппаратное обеспечение и научитесь выбирать значения датчиков и вести полезную историческую запись.
  3. После добавления возможностей HTTP-сервера и других полезных веб-ресурсов в проект вы опубликуете значения датчиков, собранные в Интернете.
  4. Затем вы будете обрабатывать постоянство выбранных данных в датчике, чтобы они могли возобновить работу после простоя или обновления программного обеспечения.
  5. Следующий шаг научит вас, как добавить уровень безопасности, требующий аутентификации пользователя для доступа к конфиденциальной информации в верхней части приложения.
  6. На последнем шаге вы узнаете, как преодолеть одно из основных препятствий в шаблоне запросов / ответов, используемых HTTP, а именно, как отправлять события с сервера на клиент.

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

Raspberry Pi

Подготовка Raspberry Pi к сенсорному проекту

Чтобы настроить Raspberry Pi, перейдите по ссылке http://www.raspberrypi.org/help/faqs/#buyingWhere .

В этом руководстве вы увидите использование модели B со следующим:

  • SD-карта с установленной операционной системой Raspbian
  • Настроенный доступ к сети, включая Wi-Fi, если используется
  • Учетные записи пользователей, пароли, права доступа, часовые пояса и т. Д. Все настроено правильно

Проект датчика будет разработан на удаленном ПК с использованием C # , поскольку это современный язык программирования, который обеспечивает полную гибкость с IoT. Он также позволяет обмениваться кодом между платформами Windows, Linux, Macintosh, Android и iOS.

Как только проект скомпилирован, исполняемые файлы размещаются на соответствующем Raspberry Pi и затем выполняются. Поскольку код работает в .NET, можно использовать любой язык из большого количества CLI-совместимых языков.

Наконечник

Инструменты разработки для C # можно скачать бесплатно с http://xamarin.com/ .

Чтобы подготовить Raspberry к выполнению кода .NET, вам необходимо установить Mono, который содержит Common Language Runtime для .NET, который поможет вам запустить код .NET на Raspberry. Это можно сделать, выполнив следующие команды в окне терминала в Raspberry Pi:

1
2
3
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install mono-complete

Теперь ваше устройство готово для запуска кода .NET.

Аппаратное обеспечение: датчик, используемый в проекте Raspberry Pi IoT

Прототип датчика будет измерять три вещи: свет, температуру и движение. Подводя итог, вот краткое описание компонентов:

  • Датчик освещенности представляет собой простой аналоговый датчик ZX-LDR, который подключается к четырехканальному аналого-цифровому преобразователю (Digilent Pmod AD2). Затем он подключается к шине I 2 C, которая будет подключаться к стандартным выводам GPIO для I 2 C. Обратите внимание, что шина I2C позволяет осуществлять связь с несколькими цепями, используя синхронную связь, используя последовательную линию синхронизации (SCL) и последовательную линию передачи данных ( ПДД) пин. Это распространенный способ связи с интегральными схемами.
  • Датчик температуры (Texas Instruments TMP102) подключается напрямую к той же шине I 2 C.
  • В выводах SCL и SDA на шине I 2 C используются рекомендованные подтягивающие резисторы, чтобы гарантировать, что они находятся в высоком состоянии, когда никто активно их не опускает.
  • Инфракрасный детектор движения (PIR-датчик Parallax) представляет собой цифровой вход, который можно подключить к GPIO 22.
  • Четыре светодиода также будут добавлены к плате. Один из них зеленый и подключен к GPIO 23. Это покажет, когда приложение работает. Второй – желтый и подключен к GPIO 24. Это покажет, когда измерения будут выполнены. Третий – желтый и подключен к GPIO 18. Показывает, когда выполняется HTTP-операция. Последний красный и подключен к GPIO 25. Это покажет, когда происходит ошибка связи.
  • Контакты, управляющие светодиодами, сначала подключаются к резисторам 160 Ом, прежде чем они подключаются к светодиодам, а затем к земле. Все оборудование платы-прототипа питается от источника 3,3 В от Raspberry Pi. Резистор 160 Ом, подключенный последовательно между контактом и землей, гарантирует, что светодиод излучает яркий свет.

Наконечник

Для введения в GPIO на Raspberry Pi, пожалуйста, обратитесь к http://www.raspberrypi.org/documentation/usage/gpio/ .

Два руководства по выводам GPIO можно найти по адресу http://elinux.org/RPi_Low-level_peripherals .

Для получения дополнительной информации см. Http://pi.gadgetoid.com/pinout .

На следующем рисунке показана принципиальная схема платы-прототипа:

Raspberry Pi

Взаимодействие с оборудованием

Взаимодействие с оборудованием осуществляется с помощью соответствующих классов, определенных в библиотеке Clayster.Library.RaspberryPi. Например, цифровой выход обрабатывается с использованием класса DigitalOutput, а цифровой вход – с классом DigitalInput. Устройства, подключенные к шине I 2 C, обрабатываются с использованием класса I 2 C. Существуют также другие универсальные классы, такие как ParallelDigitalInput и ParallelDigitalOutput, которые одновременно обрабатывают ряд цифровых входов и выходов.

Класс SoftwarePwm обрабатывает программно управляемый выход с широтно-импульсной модуляцией. Класс Uart управляет связью, используя порт UART, доступный на Raspberry Pi. Существует также подпространство под названием «Устройства», в котором доступны классы устройств.

В конце концов, все классы взаимодействуют со статическим классом GPIO, который используется для взаимодействия со слоем GPIO в Raspberry Pi.

Каждый класс имеет конструктор, который инициализирует соответствующий аппаратный ресурс, методы и свойства для взаимодействия с ресурсом, а также метод Dispose, который освобождает ресурс.

Наконечник

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

Интерфейс оборудования

Аппаратные интерфейсы для светодиодов следующие:

1
2
3
4
private static DigitalOutput executionLed = new DigitalOutput (23, true);
private static DigitalOutput measurementLed = new DigitalOutput (24, false);
private static DigitalOutput errorLed = new DigitalOutput (25, false);
private static DigitalOutput networkLed = new DigitalOutput (18, false);

Используйте класс DigitalInput для детектора движения:

1
private static DigitalInput motion = new DigitalInput (22);

С температурным датчиком на шине I 2 C, который ограничивает тактовую частоту последовательного интерфейса максимум 400 кГц, подключите его следующим образом:

1
2
3
private static I2C i2cBus = new I2C (3, 2, 400000);
private static TexasInstrumentsTMP102 tmp102 =
           new TexasInstrumentsTMP102 (0, i2cBus);

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

1
2
private static AD799x adc =
         new AD799x (0, true, false, false, false, i2cBus);

Внутреннее представление значений датчика

Значения данных датчика будут представлены следующим набором переменных:

1
2
3
4
private static bool motionDetected = false;
private static double temperatureC;
private static double lightPercent;
private static object synchObject = new object ();

Исторические ценности также будут сохранены для анализа тенденций:

1
2
3
4
5
private static List<Record> perSecond = new List<Record> ();
private static List<Record> perMinute = new List<Record> ();
private static List<Record> perHour = new List<Record> ();
private static List<Record> perDay = new List<Record> ();
private static List<Record> perMonth = new List<Record> ();

Постоянные данные

Сохранять данные просто. Это делается с использованием объектной базы данных . Эта объектная база данных анализирует определение класса объектов для сохранения и динамически создает схему базы данных для размещения объектов, которые вы хотите сохранить. База данных объектов определена в Clayster.Library.Data library . Сначала вам нужна ссылка на объектную базу данных, которая выглядит следующим образом:

1
internal static ObjectDatabase db;

Затем вам необходимо предоставить информацию о том, как подключиться к базовой базе данных. Это можно сделать в файле .config приложения или в самом коде. Укажите базу данных SQLite и укажите необходимые параметры в коде при запуске:

1
2
3
DB.BackupConnectionString = "Data Source=sensor.db;Version=3;";
DB.BackupProviderName = "Clayster.Library.Data.Providers."
                      + "SQLiteServer.SQLiteServerProvider";

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

1
db = DB.GetDatabaseProxy ("TheSensor");

После этого датчик не потеряет данные, если Raspberry Pi будет перезапущен.

Внешнее представление значений датчика

Чтобы облегчить обмен данными датчиков между устройствами, вам потребуется совместимый формат данных датчиков на основе XML, предоставленный в библиотеке Clayster.Library.IoT . Здесь данные датчика состоят из набора узлов, которые сообщают данные, упорядоченные в соответствии с отметкой времени.

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

Пространство имен Clayster.Library.IoT.SensorData помогает вам экспортировать информацию о датчиках, предоставляя абстрактный интерфейс ISensorDataExport. Эта же логика может быть позже использована для экспорта в различные форматы данных датчика. Библиотека также предоставляет класс с именем ReadoutRequest, который предоставляет информацию о том, какой тип данных требуется. Вы можете использовать это, чтобы адаптировать экспорт данных к желаниям запрашивающей стороны.

Экспорт данных датчика

Экспорт начинается с вызова метода Start() в модуле экспорта данных датчика и заканчивается вызовом метода End() . Между этими двумя выполняется последовательность StartNode() и EndNode() , по одному для каждого экспортируемого узла.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
private static void ExportSensorData (ISensorDataExport Output,
                                      ReadoutRequest Request)
{
  Output.Start ();
  lock (synchObject)
   {
    Output.StartNode ("Sensor");
    Export (Output, new Record[]
      {
        new Record (DateTime.Now, temperatureC, lightPercent, motionDetected)
      },ReadoutType.MomentaryValues, Request);
 
      Export (Output, perSecond, ReadoutType.HistoricalValuesSecond, Request);
      Export (Output, perMinute, ReadoutType.HistoricalValuesMinute, Request);
      Export (Output, perHour, ReadoutType.HistoricalValuesHour, Request);
      Export (Output, perDay, ReadoutType.HistoricalValuesDay, Request);
      Export (Output, perMonth, ReadoutType.HistoricalValuesMonth, Request);
      Output.EndNode ();
  }
  Output.End ();
}

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

Учить больше:

Как использовать OpenCV с Raspberry Pi

Как построить проект IoT с использованием Raspberry Pi и Artik

Метод Export экспортирует перечисление объектов Record. Сначала он проверяет, требуется ли клиенту соответствующий тип считывания, прежде чем экспортировать данные этого типа. Метод также проверяет, находятся ли данные в запрошенном интервале времени и что поля представляют интерес для клиента.

Если поле данных проходит все эти тесты, оно экспортируется путем вызова любого из экземпляров перегруженного метода ExportField (), доступного в объекте экспорта данных датчика. Поля экспортируются между EndTimestamp() методов EndTimestamp() StartTimestamp() и EndTimestamp() , определяя EndTimestamp() метку, которая соответствует экспортируемым полям:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static void Export(ISensorDataExport Output, IEnumerable History,
                           ReadoutType Type,ReadoutRequest Request)
{
  if((Request.Types & Type) != 0)
  {
   foreach(Record Rec in History)
   {
    if(!Request.ReportTimestamp (Rec.Timestamp))
     continue;
 
    Output.StartTimestamp(Rec.Timestamp);
    if (Request.ReportField("Temperature"))
      Output.ExportField("Temperature",Rec.TemperatureC, 1,"C", Type);
    if(Request.ReportField("Light"))
      Output.ExportField("Light",Rec.LightPercent, 1, "%", Type);
 
    if(Request.ReportField ("Motion"))
      Output.ExportField("Motion",Rec.Motion, Type);
 
    Output.EndTimestamp();
   }
  }
}

Вы можете протестировать метод, экспортировав некоторые данные датчика в XML, используя класс SensorDataXmlExport. Он реализует интерфейс ISensorDataExport. Результат будет выглядеть примерно так, если вы экспортируете только мгновенные и исторические дневные значения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0"?>
<fields xmlns="urn:xmpp:iot:sensordata">
  <node nodeId="Sensor">
    <timestamp value="2014-07-25T12:29:32Z">
      <numeric value="19.2" unit="C" automaticReadout="true"
                            momentary="true" name="Temperature"/>
      <numeric value="48.5" unit="%" automaticReadout="true"
                            momentary="true" name="Light"/>
      <boolean value="true" automaticReadout="true"
                            momentary="true" name="Motion"/>
    </timestamp>
    <timestamp value="2014-07-25T04:00:00Z">
      <numeric value="20.6" unit="C" automaticReadout="true"
                            name="Temperature" historicalDay="true"/>
      <numeric value="13.0" unit="%" automaticReadout="true"
                            name="Light" historicalDay="true"/>
      <boolean value="true" automaticReadout="true"
                            name="Motion" historicalDay="true"/>
    </timestamp>
   ...
  </node>
</fields>

Если вам понравилось читать этот учебник и вы хотите подробно изучить Интернет вещей, вы можете изучить книгу Питера Вара « Изучение Интернета вещей ». Книга следует практическому подходу и демонстрирует создание нескольких IoT-проектов, включая приводы, камеры, контроллеры и многое другое. Если вы являетесь энтузиастом IoT или разработчиком, заинтересованным в изучении основ IoT, эта книга обязательна для вашего котенка.

Опубликовано на Java Code Geeks с разрешения Франческо Аццолы, партнера по нашей программе JCG. См. Оригинальную статью здесь: Узнайте, как IoT создает проект сенсора с Raspberry Pi и сенсорами

Мнения, высказанные участниками Java Code Geeks, являются их собственными.