Понадобилось нам однажды измерять температуру и влажность в одном помещении, несложная задача, стоит обратиться в гугл и там до кучи примеров на ардуино как это сделать, скетчи, схемы и пояснения. Простые задачи подобного рода возникают достаточно часто и каждый раз модифицировать код для контроллера не хотелось. Мы подумали, а что если написать что-то типа интерпретатора для микроконтроллера(МК), который бы принимал команды и выполнял их. Таким образом отпадает необходимость писать софт каждый раз для МК, это занятие требует времени зачастую больше, чем под ПК из-за того, что объем памяти МК ограничен и не попользуешься развитыми средствами типа regex и прочего. Интерпретатор должен быть расширяемый, то есть добавление новой команды, не должно быть зубодробительной операцией. Также в будущем он должен быть легко переносим на ARM Cortex-M3 архитектуру и способен работать через различные интерфейсы связи будь то RS485, Ethernet, ZigBee.
На основании этих требований было решено разработать такое устройство и + библиотеки для работы с ним под несколько языков (сейчас Python и GCC C/C++) и ОС ( Win и Linux) чтобы не париться больше с написанием каждый раз софта для контроллера, который делает рутину — собирает данные или что-то включает или выключает.
Рис. 1. Контроллер MeteoBoard
Проще говоря, хотелось сделать такое устройство, которое не нужно вечно прошивать, переписывать код прошивки, и снова прошивать чтобы адаптироваться под новую задачу. Хотелось управлять простыми командами и все логику управления вынести в программу на ПК. Последней преградой на этом пути оказался интерфейс, через которое устройство будет подключено к ПК. Нам не очень то хотелось разбираться с USB портами, с драйверами и конечными точками, это только усложнило бы работу с устройством, поэтому было решено поднять на МК открытый USB стэк и производить обмен данными между устройством и ПК через виртуальный COM-порт, который появляется в системе каждый раз, когда мы будем подключать плату к ПК. Работать с COM-портом уже более комфортно по сравнению с USB, но мы решили пойти дальше и написали библиотеку, которая берет на себя всю черновую работу по нахождению порта, к котором подключена плата и его инициализации, при этом выдает пользователю только полезные данные с датчиков устройства.
Конечно, иногда такой подход, когда вся логика управления вынесена на более высокий уровень, неприемлем, например, требуется разработать полностью автономную систему управления чем либо, но такие задачи встречаются реже и у нас не этот случай.
Железо
Для проверки выбранного подхода была спроектирована печатная плата на базе микроконтроллера ATMEGA32U4 с аппаратным USB 2.0. На плату были установлены следующие датчики:
- Датчик давления BMP085. Измеряет давление, температуру и высоту над уровнем моря(!), использую, видимо, барометрическую формулу. Может измерять давление в диапазоне 30-110 кПа, работает на разных высотах от +9000 м над уровнем моря и до -500 м ниже уровня моря
- Датчик влажности DHT11. Измеряет влажность и температуру, не блещет точностью преобразования, но важно, что он цифровой и доступный. Влажность мерит в диапазоне от 20 до 90 %, погрешность 5%, по части измерения температуры здесь почти комнатные условия от 0 до 50 С, а погрешность 2 С
- Измерение освещенности происходит с помощью фоторезистора. Сигнал с фоторезистора заведен на канал АЦП, и в зависимости от освещения напряжение с фоторезистора меняется. Сама зависимость нелинейная, поэтому в контроллере дополнительно происходит калибровка. На выходе программист получает рафинированные данные от 0 до 255, 0 — если темно «хоть глаз выколи » и 255 если фотоэлемент засвечен
- Измерение температуры производится датчиками DS18b20. Их температурный диапазон от -55 до 125 С, но я думаю резиновый кожух, которым покрыт выносной датчик такую температуру не выдержит, максимум +70, а при отрицательной температуре ниже 30, кожух может потрескаться, если его не аккуратно перемещать. Точность 0.5 С. Длина провода в нашем случае составляла 2 метра, предельная длина зависит от среды, с нормальным экранированным кабелем можно достичь и 50 метров, всего датчиков на плату устанавливается 3 (белый контакт на плате, один установлен, два не запаяны)
Когда частично это было запаяно началась работа над софтом. Нам хотелось чтобы интерпретатор, который выполняет команды мог быть легко перенесет на другое железо, если нам вдруг потребуется масштабироваться, например, нужно будет измерять температуру не в 3 местах, а в 10, код должен работать без изменений. Каждому датчику был задан идентификационный номер Device ID, а также список актуальных параметров Param ID, чтобы можно было без коллизий обращаться к любому датчику. Например, для датчика давления device ID = 5, параметры могут быть следующие:
1 для температуры, 3 для атмосферного давления и 4 для альтитуда.
Рис. 2. Датчики устройства
Датчик | Device ID | Parameter ID | Описание |
---|---|---|---|
DS18b20 #1 | 001 | 001 | Температура (точность 0.5 С) |
DS18b20 #2 | 002 | 001 | Температура (точность 0.5 С) |
DS18b20 #3 | 003 | 001 | Температура (точность 0.5 С) |
DHT11 | 004 | 001 002 |
Температура (точность 2 C) Влажность (точность 5 %) |
BMP085 | 005 | 001 003 004 |
Температура (точность 0.1 C) Давление, Па Альтитуда, м |
Датчик освещенности | 010 | 223 | Цифровой диапазон от 0 до 255 |
Табл. 1 Команды и параметры
Рис. 3 Обмен данными между ПК и устройством MeteoBoard
Эта таблица в дальнейшем будет только увеличиваться по мере появления новых контроллеров со специфичными требованиями, но главное, что все контроллеры работают по унифицированному набору команд, значит код для ПК однажды написанный может легко работать на новом девайсе (если, конечно, физически есть такой датчик на плате). Здесь нет зависимости от типа микросхемы, ее производителя и тд. Если какой-то датчик выдает температуру, значит передав контроллеру пакет, который содержит device ID этого датчика и следом 001 мы всегда получим температуру в градусах Цельсия и это для любого параметра, который есть и будет в таблице.
Программное обеспечение
Работать с MeteoBoard можно практически на любом языке, который может обращаться к COM-порту. Это могут быть даже скриптовые языки типа Perl и Python. Доступ к аппаратуре можно получить из любого пользовательского приложения через библиотеку для работы с устройством, в данный момент есть библиотеки для C и Python.
Например, чтобы считать температуру на одном из датчиков нужно вызвать функцию getDHT11_temp(port), а эта функция уже самостоятельно производит обмен данными с тем датчиком с которым нужно. Для того, чтобы функция «знала» к какому COM-порту подключено устройство мы сначала сканируем все доступные COM-порты и отправляем туда специальные запросы — тот порт, который ответил — нас интересует, на нем сидит устройство, с ним дальше и работаем.
1) Python
Как выглядит минимальное приложение, которое работает с MeteoBoard?
Вот оно:
# -*- coding: UTF-8 -*-
from meteoboardlib import * # подключаем функции для работы с устройством
port = getMeteoBoard_port() # определяем к какому порту подключена плата
print u'Температура, % = ', getDHT11_temp(port) # Считываем значения в консоль
Для Python была написана библиотека для работы с устройством, которая основана на PySerial, а значит будет работать как в Windows, так на Linux (под Linux библиотеку не тестировали еще). Работа на Python с устройством получилась особенно прозрачной, библиотека meteoboardlib.py содержит функцию для определения к какому порту подключена плата. ПК просто отправляет во все доступные порты символ 'w', и тот порт, который откликнулся строкой 'MeteoBoard' в течении 0,5с используется в дальнейшей работе.
Следующий ниже код считывает значения нескольких датчиков в текущий момент времени и выводит все это в консоль.
# meteoboard_test.py
# -*- coding: UTF-8 -*-
from meteoboardlib import * # подключаем функции для работы с устройством
port = getMeteoBoard_port() # определяем к какому порту подключена плата
# запрашиваем необходимые значения и выводим в консоль
print u'Влажность, % = ', getDHT11_temp(port)
print u'Температура, C = ',getDHT11_Hum(port)
print u'Температура, C = ',getBMP085_temp(port)
print u'Давление, Па = ',getBMP085_pressure(port)
print u'Альтитуда, м = ',getBMP085_altitude(port)
С этими данными уже можно работать как вздумается: делать частично умный дом, мониторить что-то, делать экспертную систему, возможностей масса. График ниже получен с помощью matplotlib, накопили массивы значений и plot'м отрисовали.
В самом начале видно как температура и влажность подскочили, давление и альтитуда в пределах погрешности измерения. Когда убрали воздействие, данные постепенно начали возвращаться в исходные состояния.
Рис. 4 Визуализация данных с устройства с помощью matplotlib
Можно писать данные сразу в файл, что-то типа системы логирования, а потом открывать в excel и изучать на предмет аномалий, например, в помещении.
# -*- coding: UTF-8 -*-
from meteoboardlib import *
import csv
c = csv.writer(open("MYFILE.csv", "wb"))
port = getMeteoBoard_port() # узнаем к какому порту подключена плата
# выводим заголовок таблицы
c.writerow(["humidity,% ","Temperature,C ","Temperature,C ","Pressure,Pa ","altitude,m"])
for i in range(500):
print i
c.writerow([str(getDHT11_temp(port)),str(getDHT11_Hum(port)),str(getBMP085_temp(port)),str(getBMP085_pressure(port)), str(getBMP085_altitude(port))])
Также можно в несколько строк кода писать программы, которые будут мониторить температуру, влажность и все остальные характеристики внешней среды и, в зависимости от того, что происходит в текущий момент времени со средой — реагировать согласно программе. Например, звать пожарную бригаду при повышении температуры выше критического значения
# -*- coding: UTF-8 -*-
from meteoboardlib import *
port = getMeteoBoard_port() # честно узнаем к какому порту подключена плата
temp = 0
temp = getDHT11_temp(port)
while(1):
if temp > 35:
print "Fireman save us!!! ",temp
temp = getDHT11_temp(port)
print temp
Пара строчек, а сколько удовольствия от самого процесса получения данных из реального мира, ничего не нужно паять, не нужно писать код для микроконтроллера, хотя не скрою есть и в этом что-то особенное.
Интересным направлением работы здесь может быть отправка данных с датчиков на удаленный сервер для того, чтобы иметь возможность следить за ситуацией с любого мобильного или стационарного устройства. Или участие в проекте народный мониторинг, было несколько статей на Хабре по этому вопросу 1, 2
2) GCC C/C++ компилятор
Для gcc c компилятора под Linux была написана небольшая библиотека для работы с устройством, которая основана на RS-232 for Linux and Windows library. Вся дальнейшая работа проводилась на Linux Ubuntu 12.04, но по идее должно также работать на Windows (тестов на Windows не делали). К сожалению, получить номер порта к которому подключена плата в автоматическом режиме пока не получилось, в отличии от библиотеки на Python, здесь порт задается руками, а функция-заглушка для определения порта просто выдает константу.
Чтобы получить данные с устройства нужно подключить библиотеки, получить номер порта (задать руками) и пользоваться функциями.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "rs232.h"
#include "meteoboard.h"
int main()
{
int cport_nr, bdrate=19200;
cport_nr = getMeteoBoard_port(); // получаем порт(функция заглушка)
if(OpenComport(cport_nr, bdrate)) // пробуем открыть порт, не открывается завершаем работу
{
printf("Invalid ComPortn");
return(0);
}
while(1)
{
printf("%d %d %d %d %dn",getDHT11_temp(cport_nr), getDHT11_Hum(cport_nr), getBMP085_temp(cport_nr),getBMP085_pressure(cport_nr), getBMP085_altitude(cport_nr));
}
return 0;
}
Если необходимо визуализировать данные, то как мне показалось достаточно быстрым является следующий способ: пишем данные в текстовый файл в столбец, а затем отображаем с помощью gnuplot.
gnuplot>> plot «data.txt»
Получаем такой график, здесь вначале я дышу на датчик DHT11, а потом дую на него феном и сушу воздух, по оси y проценты влажности, по х просто отчеты, их можно делать с любой периодичностью.
Рис. 5 Визуализация данных с помощью gnuplot
3) Путь Джедая, или выбери инструмент себе сам
Так как работа с СОМ-портом это достаточно древняя технология (но до сих пор активно использующаяся из-за простоты, надежности и легкой реализации) то библиотек написанных для этих целей под разные языки много. Чтобы работать с устройством на любом привычном языке нужно сформировать пакет согласно таблице, отправить его в порт, к которому подключена плата, подождать примерно 10 мс, а затем получить пакет с нужной информацией. Хорошие модули для работы с виртуальными COM-портами есть для Qt QtSerialPort, для perl Device:SerialPort, для Delphi ComPort Library и др.
Применение:
На самом деле область применения такого контроллера достаточно широка: можно написать экспертную систему, которая будет собирать данные о реальном внешнем мире и делать предсказания, например, погоды, в данном случае. Также можно применить эту систему для мониторинга в производственном помещении. Конечно, некоторые датчики имеют не ахти какие параметры (DHT11, 5% погрешность влажности), но в большинстве случаев и этого достаточно, чтобы вовремя просигнализировать, что «крыша то на складе прохудилась» и кругом лужи. Можно выдавать данные на какой-нибудь удаленный сервер, например, в проект «народный мониторинг.» С помощью MeteoBoard можно видеть как изменяется влажности в квартире, когда кипит чайник, когда открыта форточка, когда пришла куча друзей и надышали в комнате, это тоже датчик замечает. Возможностей масса, все зависит от фантазии разработчика.
Очень рад, что удалось сделать такой классный девайс, теперь благодаря его возможностям сможем решать свои задачи эффективнее и с меньшими затратами времени.
Я и без коровы был счастлив, а с коровой буду вдвойне счастливей!
(с)Кот Матроскин
Видео 1. Считывание данных с устройства в консоль
Linux Ubuntu 12.04, GCC C
Видео 2. Работа с устройством через Python-код
Вин7, Python2.7 + PySerial
Дополнительная и информация
1)Библиотека MeteoBoard ссылка на GitHub
2)RS-232 for Linux and Windows
3)PySerial for Python
4)Perl COM-port lib
Благодарность
Огромное спасибо за поддержку и возможность работы в профессиональном коллективе собственно
ага, вот эти ребята и еще здесь
UPD: Большая просьба отвечать на опросник
Автор: avrfun