Цель работы

Создание метеостанции и визуализации данных в виртуальной среде

Введение

На третьем курсе радиофизического факультета я начал изучать такие дисциплины как: Blender, C++, Unreal Engine.

Blender -  профессиональное свободное и открытое программное обеспечение для создания трехмерной компьютерной графики, включающее в себя средства моделирования, скульптинга, анимации, симуляции, рендеринга, постобработки и монтажа видео со звуком, компоновки с помощью «узлов» (Node Compossiting), а также создания 2D-анимаций. 

C++ -компилируемый, статически типизированный язык программирования общего назначения. Поддерживает такие парадигмы программирования, как процедурное программирование, объектно-ориентированное программирование, обобщённое программирование, обеспечивает модульность, раздельную компиляцию, обработку исключений, абстракцию данных, объявление типов (классов) объектов, виртуальные функции.

Unreal Engine — игровой движок, разрабатываемый и поддерживаемый компанией Epic Games. Написанный на языке С++, движок позволяет создавать игры для большинства операционных систем и платформ.

Описание используемых плат, датчиков 

Наша метеостанция состоит из таких компонент как:

Arduino Mega 2560 –  самая функциональная платформа компании, предназначенная для создания различных микроэлектронных устройств. Функционал устройства позволяет создавать большие проекты, в которых требуется задействовать много периферийных устройств. Плата позволяет одновременно задействовать сотни датчиков и сенсоров, а мощный контроллер – быстро и эффективно обрабатывать с них данные.

Микросхема ESP8266 – один из самых популярных инструментов для организации беспроводной связи в проектах умного дома. С помощью беспроводного контроллера можно организовывать связь по интерфейсу WiFi, обеспечивая проектам Arduino выход в интернет и возможность дистанционного управления и сбора данных. На основе ESP8266 созданы такие популярные платы как WeMos и NodeMcu, а также огромное количество самодельных проектов.

Датчик BME280– датчик атмосферного давления, влажности и температуры.

Датчик MQ-2 – датчик газа/дыма.

Датчик MH-Z19 – датчик углекислого газа.

Описание общего принципа работы метеостанции: сбор данных, передача данных на сервер

Датчики подключаются по проводам к пинам Arduino Mega. Например, датчик BME280 подключается по I2C- последовательная асимметричная шина для связи между интегральными схемами внутри электронных приборов. Использует две двунаправленные линии связи (SDA и SCL), применяется для соединения низкоскоростных периферийных компонентов с процессорами и микроконтроллерами (например, на материнских платах, во встраиваемых системах, в мобильных телефонах).
Для каждого датчика существует написанная библиотека, которая есть в открытом доступе. Именно эти готовые библиотеки позволяют нам без лишних усилий опросить датчики.
В скетче для Arduino Mega создана функция readSensors() , которая вызывается каждые 5000 милисекунд


arduTimer.setEventHandler(0,&readSensors);
arduTimer.execRepeated(0,5000);


Эта функция получает значения со всех датчиков и формирует строку со значениями:


&co2Ppm=380&dust=24&airQual=221&bmeTemp=27.10&bmeHum=29.30&bmePres=99.52

Эта строка отправляется по последовательному интерфейсу Serial2 на ESP8266.

Монитор порта Arduino Mega:

Диапазон концентраций для датчика Co2:

— 350 — 450 ppm: Нормальный уровень на открытом воздухе.
— < 600 ppm: Приемлемые уровни. Уровень. рекомендованный для спален, детских садов и школ.
— 600 — 1000 ppm: Жалобы на несвежий воздух, возможно снижение концентрации внимания.
— 1000 ppm: Максимальный уровень стандартов ASHRAE (American Society of Heating, Refrigerating and Air-Conditioning Engineers) и OSHA (Occupational Safety & Health Administration).
— 1000 — 2500 ppm: Общая вялость, снижение концентрации внимания, возможна головная боль.
— 2500 — 5000 ppm: Возможны нежелательные эффекты на здоровье.

Стоит отметить, что перед началом работы датчика MH-Z19 (Co2) его стоит откалибровать. Это можно сделать после установки библиотеки MHZ19.h. После этого нужно перейти в Файл/Примеры/MH-Z19/Calibration.

После этого загрузить скетч на плату, к которой подключен датчик.


При запуске ESP8266 пытается подключится к wi-fi сети, имя и пароль которой хранится в EEPROM. Библиотека EEPROM позволяет сохранять настройки платы в энергонезависимой памяти, после того, как пользователь их изменил.
В скетче для ESP8266 создана функция poolDHT() , которая вызывается в основном цикле программы и записывает значение температуры и влажности в глобальные переменные
float var_h = 0; // Влажность
float var_t = 0; //Температура

с периодом, заданным нами.


//Интервал опроса датчика в милисекундах
#define DHT_INTERVAL 5000


В основном цикле программы идет прием строки по последовательному интерфейсу с Arduino Mega. Эта строка записывается в глобальную переменную mega_str_get и добавляется к строке get запроса передаваемого на сервер.
Функция poolHTTPclient() ,созданная в скетче, вызывается в основном цикле программы и с периодом, настраиваемом нами и отпраляет get запросы на сервер. Для передачи данных с ESP8266 на сервер используется библиотека WiFiClient.h. 

Создание сервера для получения данных с датчиков

Сервер размещен на хостинге (sprinthost.ru). Для написания сервера используется язык .php . На сервере используется база данных MySQL.

Общий принцип работы: при приеме данных с нового устройства создается таблица, с названием, содержащим имя устройства. Если таблица уже существует, то данные дописываются в нее.

Рассмотрим основные скрипты:

add_log.php – прием get запроса от устройств и запись данных в базу

Код:

include ('db.php');


//Добавляет измерения в таблицу базы данных
function AddLog($var_t,$var_h, $device, $co2Ppm, $dust, $airQual, $bmeTemp, $bmeHum, $bmePres)
{//$device - название таблицы в базе данных
//Создаем таблицу в базе, если она не существуйет


$query = "CREATE TABLE IF NOT EXISTS `device_".$device."` (`id` INT NOT NULL AUTO_INCREMENT , `date` VARCHAR(50) NOT NULL , `var_t` FLOAT NOT NULL , `var_h` FLOAT NOT NULL , `co2Ppm` FLOAT NOT NULL , `dust` FLOAT NOT NULL , `airQual` FLOAT NOT NULL , `bmeTemp` FLOAT NOT NULL , `bmeHum` FLOAT NOT NULL , `bmePres` FLOAT NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;";


$result = mysqli_query($GLOBALS['connection'],$query);
if (!$result) {
echo "mysqli_query error"."\n";
echo "Error code errno: ".mysqli_errno($GLOBALS['connection']).PHP_EOL;
echo "Error text error: ".mysqli_error($GLOBALS['connection']).PHP_EOL;
}

//Вставляем данные в таблицу
$date = date("Y-m-d H:i:s");
$query = "INSERT INTO `device_".$device."` (`id`, `date`, `var_t`, `var_h`, `co2Ppm`, `dust`, `airQual`, `bmeTemp`, `bmeHum`, `bmePres`) VALUES (NULL, '".$date."', '".$var_t."', '".$var_h."', '".$co2Ppm."', '".$dust."', '".$airQual."', '".$bmeTemp."', '".$bmeHum."', '".$bmePres."');";

$result = mysqli_query($GLOBALS['connection'],$query);

if (!$result) {
echo "mysqli_query error"."\n";
echo "Error code errno: ".mysqli_errno($GLOBALS['connection']).PHP_EOL;
echo "Error text error: ".mysqli_error($GLOBALS['connection']).PHP_EOL;

mysqli_query($GLOBALS['connection'],"DROP TABLE IF EXISTS `device_".$device."`");
if ($result) echo "++++++++++++++++++++ drop table +++++++++++++++++++++++ ".$device;
}

echo '{"device":"'.$device.'", "var_t":"'.$var_t.'", "var_h":"'.$var_h.'", "date":"'.$date.'"';
echo '"co2Ppm":"'.$co2Ppm.'", "dust":"'.$dust.'", "airQual":"'.$airQual.'"';
echo '"bmeTemp":"'.$bmeTemp.'", "bmeHum":"'.$bmeHum.'", "bmePres":"'.$bmePres.'"';
echo'"}';
}


if ( isset( $_GET["device"] ) )
{
$device = $_GET["device"];
$var_t = $_GET["var_t"];
$var_h = $_GET["var_h"];
$co2Ppm = $_GET['co2Ppm'] = isset($_GET['co2Ppm']) ? $_GET['co2Ppm'] : '-999';
$dust = $_GET['dust'] = isset($_GET['dust']) ? $_GET['dust'] : '-999';
$airQual = $_GET['airQual'] = isset($_GET['airQual']) ? $_GET['airQual'] : '-999';
$bmeTemp = $_GET['bmeTemp'] = isset($_GET['bmeTemp']) ? $_GET['bmeTemp'] : '-999';
$bmeHum = $_GET['bmeHum'] = isset($_GET['bmeHum']) ? $_GET['bmeHum'] : '-999';
$bmePres = $_GET['bmePres'] = isset($_GET['bmePres']) ? $_GET['bmePres'] : '-999';

//AddLog($var_t,$var_h, $device);
AddLog($var_t,$var_h, $device, $co2Ppm, $dust, $airQual, $bmeTemp, $bmeHum, $bmePres);
//echo $device;//"{"\"device\":\""+$device"\"}";
}
else
{
echo "device not defined";
}

 

db.php – содержит данные для доступа к базе данных и выполняет подключение к ней

Код:

$host = 'localhost';
$user = '********';
$pswd = 'kaban123';
$db = '*********';//

$GLOBALS['connection'] = mysqli_connect($host,$user,$pswd,$db);


mysqli_set_charset ( 'utf8');//&connection,


if (!$GLOBALS['connection']){// || !mysqli_select_db($db, $connection)){
echo "Error: Unable to establish connection with MySQL." . PHP_EOL;
echo "Error code errno: " . mysqli_connect_errno() . PHP_EOL;
echo "Error text error: " . mysqli_connect_error() . PHP_EOL;
exit;
}

forUnreal.php - скрипт для взаимодействия с Unreal Engine (приложение VR)

Код:

$host = 'localhost';
$user = '***********';
$pswd = 'kaban123';
$db = '***********';//

$conn = mysqli_connect($host, $user, $pswd, $db) or die("connection error");


$measuresSQL = "SELECT * FROM device_dht11 ORDER BY id DESC";
$measuresResult = $conn->query($measuresSQL);
$arr_measures = array();

while ( $item = mysqli_fetch_array( $measuresResult ) )
{
$date = $item['date'];
$var_t = $item['var_t'];
$var_h = $item['var_h'];
$co2Ppm = $item['co2Ppm'];
$dust = $item['dust'];
$airQual = $item['airQual'];
$bmeTemp = $item['bmeTemp'];
$bmeHum = $item['bmeHum'];
$bmePres = $item['bmePres'];
$measures = array('date' => $date, 'var_t' => $var_t, 'var_h' => $var_h, 'co2Ppm' => $co2Ppm, 'dust' => $dust, 'airQual' => $airQual, 'bmeTemp' => $bmeTemp, 'bmeHum' => $bmeHum, 'bmePres' => $bmePres);
array_push($arr_measures, $measures);
}
$JsonArray=array('Body' => $arr_measures);
echo json_encode($JsonArray);

mysqli_close($conn);

Если перейти по ссылке http://a0437892.xsph.ru/index.php , то можно оказаться на сайте MeteoStation.

Логин:admin

Пароль:kaban123

После ввода логина и пароля мы попадем на страницу, где размещены данные с нашей метеостанции.

Столбцы «Температура» и «Влажность» использовались для теста. Данные передавались с тестового датчика dht11 (датчик температуры и влажности).

Создание 3D модели метеостанции

Для создания модели метеостанции используется Blender. В нашей метеостанции будут отображены основные компоненты, такие как:

корпус метеостанции

кулер

Arduino Mega 2560

Датчик MQ-2

Датчик BME280

Датчик MH-Z19

Дисплей

Кнопка включения/выключения

Далее собираем 3D модель метеостанции:

Располагаем датчики и плату внутри метеостанции

В итоге получаем готовую 3D модель метеостанции

Расположение метеостанции в виртуальном пространстве, осуществление взаимодействия с ней

 Для осуществления взаимодействия с нашей метеостанцией в VR используем Unreal Engine. Вся логика данной метеостанции написана на Blueprints.

Blueprints - это скриптовая система в Unreal Engine 4, которая представляет собой визуальный интерфейс для создания элементов геймплея. Система очень гибкая и очень мощная, и позволяет дизайнерам использовать концепцию и почти полный потанциал программирования.

С помощью Блупринтов, разработчики могут создавать такие вещи, как:

После импорта метеостанции из Blender в игровой движок Unreal Engine она имеет следующий вид:

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

Например, Blueprint для вращения лопастей кулера:

Для взаимодействия Unreal Engine и данных, которые мы передали на сервер, используется плагин VaRest. Проект VaRest - это open-source плагин к движку Unreal Engine 4 для обеспечения REST коммуникаций между клиентом и сервером, используемый десятками проектов по всему миру. Для получения данных с сервера в приложении Unreal Engine с определенной периодичностью отправляется запрос по протоколу http, в ответ, на который сервер отправляет данные в виде json объекта (скрипт forUnreal, см. выше).

В итоге мы получаем данные с датчиков в VR на нашей метеостанции: