В последнее время популярны гаджеты, показывающие уровень CO2, равно как и статьи, рассказывающие как монитор CO2 можно превратить в подключенный к компьютеру датчик. Я хочу показать решение задачи с другой стороны.
В отличие от старых датчиков CO2, MH-Z19 не требует специфического напряжения или высокой мощности и умеет передавать данные через UART и PWM.
Не то, чтобы я не доверял PWM, но лучше получать данные в цифре и с контрольной суммой. UART позволяет запрашивать уровень концентрации CO2 и заниматься двумя видами калибровки. Оставим калибровку Гаррусу и рассмотрим запрос данных. Для этого на скорости 9600 (8 bit, stop — 1, parity — none) нужно отправить следующие девять байт:
• 0xFF — начало любой команды
• 0x01 — первый сенсор (он всего один)
• 0x86 — команда
• 0x00, 0x00, 0x00, 0x00, 0x00 — данные
• 0x79 — контрольная сумма.
В ответ придет что-то такое:
• 0xFF — начало любого ответа
• 0x86 — команда
• 0x01, 0xC1 — старшее и младшее значение (256 * 0x01 + 0xC1 = 449)
• 0x3C, 0x04, 0x3C, 0xC1 — в документации сказано, что должно приходить что-то типа 0x47, 0x00, 0x00, 0x00, но на деле приходит непонятно что.
• 0x7B — контрольная сумма.
Контрольная сумма считается следующим образом: берутся 7 байт ответа (все кроме первого и последнего), складываются, инвертируются, увеличиваются на 1: 0x86 + 0x01… + 0xC1 = 0x85, 0x85 xor 0xFF = 0x7A, 0x7A + 1 = 0x7B.
Согласно документации сенсору требуется около трех минут, чтобы выйти на рабочий режим. Первое время после включения он будет выдавать или 5000ppm, или 400ppm. После особо усердной пайки может приходить в себя несколько часов.
Сенсор реагирует на изменение концентрации CO2 с задержкой около минуты. При превышении концентрации в 5000ppm (например, вы минуту интенсивно на него дышали), он некоторое время будет выдавать ложные данные, занижая уровень CO2 — я так получал даже 80ppm.
В документации это не отражено, но не стоит запрашивать данные по UART чаще раза в 10 секунд, иначе сенсор начинает выдавать что-то странное.
Пришло время картинок. Подключим сенсор к Arduino Uno через Software Serial, TX/RX в A0/A1, питание в 5В, землю — в Gnd:
Каждое измерение идет с интервалом 10 секунд. Значения перестали прыгать когда я отошел от сенсора.
Теперь сделаем датчик мобильным. Для этого потребуется устройство с OTG и приложение типа DroidTerm.
Тут есть тонкость: чтобы связь установилась — нужно перезагрузить Arduino.
Убедившись, что все работает, уберем Arduino, заменив его на FTDI FT232RL.
Питание на датчик стоит подавать уже после подключения чтобы не было проблем с соединением.
Для отправки бинарных данных через COM-порт я использую RealTerm:
Возможно, стоит добавить управление питанием через DTR, чтобы можно было перезапускать датчик.
Полезные ссылки:
Мануал по датчику MH-Z19
Схема подключения и код для PWM
Сравнение с другим датчиком
Статья на GT про MH-Z19 и ESP8266
У меня всего один датчик и я очень не люблю разбирать то, что однажды сделал, поэтому предлагаю выбрать вам.
В отличие от старых датчиков CO2, MH-Z19 не требует специфического напряжения или высокой мощности и умеет передавать данные через UART и PWM.
- Hd — калибровка нуля начнется, если на Hd более 7 секунд подается LOW. Калибровку проводить не нужно.
- SR — не используется
- Tx — уровень сигнала — 3.3В
- Rx — тоже 3.3В (работает и с 5В, но я бы не рекомендовал)
- Vo — выходное напряжение 3.3В, не более 10мА
- PWM, данные снимаются так: длина цикла 1004мс, первые 2мс всегда HIGH, последние — всегда LOW, а «середина» пропорциональна концентрации CO2 в пределах 0 — 5000ppm (а не 2000ppm как в документации).
Cppm = 5000 * (Thigh — 2ms)/(Thigh + Tlow — 4ms)
Отмечу, что PWM — штука очень капризная, требующая аккуратной пайки и 3.3В.
- AOT — не используется
- Gnd — земля
- Vin — напряжение питания 3.6 — 5.5В (сенсор работает и выдает те же значения при питании 3.3В, но производитель настоятельно рекомендует придерживаться рамок)
Не то, чтобы я не доверял PWM, но лучше получать данные в цифре и с контрольной суммой. UART позволяет запрашивать уровень концентрации CO2 и заниматься двумя видами калибровки. Оставим калибровку Гаррусу и рассмотрим запрос данных. Для этого на скорости 9600 (8 bit, stop — 1, parity — none) нужно отправить следующие девять байт:
• 0xFF — начало любой команды
• 0x01 — первый сенсор (он всего один)
• 0x86 — команда
• 0x00, 0x00, 0x00, 0x00, 0x00 — данные
• 0x79 — контрольная сумма.
В ответ придет что-то такое:
• 0xFF — начало любого ответа
• 0x86 — команда
• 0x01, 0xC1 — старшее и младшее значение (256 * 0x01 + 0xC1 = 449)
• 0x3C, 0x04, 0x3C, 0xC1 — в документации сказано, что должно приходить что-то типа 0x47, 0x00, 0x00, 0x00, но на деле приходит непонятно что.
• 0x7B — контрольная сумма.
Контрольная сумма считается следующим образом: берутся 7 байт ответа (все кроме первого и последнего), складываются, инвертируются, увеличиваются на 1: 0x86 + 0x01… + 0xC1 = 0x85, 0x85 xor 0xFF = 0x7A, 0x7A + 1 = 0x7B.
Согласно документации сенсору требуется около трех минут, чтобы выйти на рабочий режим. Первое время после включения он будет выдавать или 5000ppm, или 400ppm. После особо усердной пайки может приходить в себя несколько часов.
Сенсор реагирует на изменение концентрации CO2 с задержкой около минуты. При превышении концентрации в 5000ppm (например, вы минуту интенсивно на него дышали), он некоторое время будет выдавать ложные данные, занижая уровень CO2 — я так получал даже 80ppm.
В документации это не отражено, но не стоит запрашивать данные по UART чаще раза в 10 секунд, иначе сенсор начинает выдавать что-то странное.
Пришло время картинок. Подключим сенсор к Arduino Uno через Software Serial, TX/RX в A0/A1, питание в 5В, землю — в Gnd:
Позаимствованный скетч, в который добавлена проверка контрольной суммы
#include <SoftwareSerial.h>;
SoftwareSerial mySerial(A0, A1); // A0 - к TX сенсора, A1 - к RX
byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
unsigned char response[9];
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
}
void loop()
{
mySerial.write(cmd, 9);
memset(response, 0, 9);
mySerial.readBytes(response, 9);
int i;
byte crc = 0;
for (i = 1; i < 8; i++) crc+=response[i];
crc = 255 - crc;
crc++;
if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) ) {
Serial.println("CRC error: " + String(crc) + " / "+ String(response[8]));
} else {
unsigned int responseHigh = (unsigned int) response[2];
unsigned int responseLow = (unsigned int) response[3];
unsigned int ppm = (256*responseHigh) + responseLow;
Serial.println(ppm);
}
delay(10000);
}
Каждое измерение идет с интервалом 10 секунд. Значения перестали прыгать когда я отошел от сенсора.
Теперь сделаем датчик мобильным. Для этого потребуется устройство с OTG и приложение типа DroidTerm.
Тут есть тонкость: чтобы связь установилась — нужно перезагрузить Arduino.
Убедившись, что все работает, уберем Arduino, заменив его на FTDI FT232RL.
Питание на датчик стоит подавать уже после подключения чтобы не было проблем с соединением.
Для отправки бинарных данных через COM-порт я использую RealTerm:
Возможно, стоит добавить управление питанием через DTR, чтобы можно было перезапускать датчик.
Полезные ссылки:
Мануал по датчику MH-Z19
Схема подключения и код для PWM
Сравнение с другим датчиком
Статья на GT про MH-Z19 и ESP8266
У меня всего один датчик и я очень не люблю разбирать то, что однажды сделал, поэтому предлагаю выбрать вам.
Что сделать с датчиком?
11% (32) |
Подключить к компьютеру и написать десктопное приложение для мониторинга |
16% (42) |
Добавить его в погодную станцию |
7% (18) |
Сделать гаджет для мобильного устройства |
63% (166) |
Добавить к нему ESP8266, превратив в минималистичный компонент для «умного дома» |
3% (7) |
Свой вариант в комментарии |
Проголосовало 265 человек. Воздержалось 40 человек.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
nochkin
Как раз получил такой же и планирую подключить с ESP8266.
Насколько этот датчик врёт? Есть какой-то другой прибор для измерения что бы сравнить?
Hellsy22
У меня не с чем сравнивать.
В комментариях на Али пишут: I compared the results with EXTECH-CO250 and MH-Z19 seems to be very accurate.
Статья, где его сравнивают с другим похожим датчиком: http://foogadgets.blogspot.com/2016/02/new-co2-sensor-support-for-wms-mk3.html
nochkin
Спасибо за линк. Предполагаю, что точность ещё может от экземпляра зависеть.
Я заказал более "взрослое" устройство для измерения CO2, но пока не получил. Попробую с ним сравнить тогда.
Hellsy22
О, будет замечательно, если вы выложите результаты сравнения.
ShtAnigga
а можно модель более "взрослого" устройства узнать?
nochkin
Обычно оно идёт как модель HT2000.
ShtAnigga
Благодарю, я почему-то подумал о другом, принципиальном решении.
Предполагал голую железку с датчиком и контроллером.
Для иных целей требуется
SergeyRyb
У нас в офисе уже почти год висит девайс на MH-Z14 (предыдущая версия датчика от того же производителя, протокол такой же) и ESP8266.
Как выглядит
Благодаря ему нашли проблемы с вентиляцией.
Сейчас уже используем MH-Z19, датчик работает стабильно, но на мой взгляд слегка занижает показания CO2 (при открытом окне через полчаса после завершения рабочего дня выдаёт 400 ppm, при том что уровень CO2 в атмосфере уже слегка превышает эту отметку), либо у нас в городе (Ярославская область) очень чистый воздух.
Duti_Fruti
Жду MH-Z14. Решил заказать его. Если это младшая модель, почему она немного дороже? У нее есть преимущества?
SergeyRyb
Кажется, мне нельзя вставлять картинки (read&comment аккаунт), поэтому вот ссылка, как выглядит девайс:
https://habrastorage.org/files/dd6/f94/c3d/dd6f94c3d4ca44888d2d287074a660b7.jpg
Вроде как из видимых отличий — только наличие DAC-выхода у MH-Z14 и более высокая скорость реакции (не очень актуально для измерения CO2, его концентрация нарастает очень плавно).
Скорее всего оптимизировали производство, сократили себестоимость и таким образом продвигают новый продукт.
Для нас MH-Z19 оказался наилучшим вариантом, т.к. имеет гораздо меньшие габариты, два окна воздухозабора и потребляет почти в 3 раза меньше энергии.
Duti_Fruti
Все ясно. Значит зря переплачивал, если он хуже или такой-же за большие деньги.
Rumlin
Напишите публикацию про это. Какой средний потребляемый ток? Как часто просыпается для измерений и передачи данных?
ShtAnigga
А брали на али или ебее? Дорогой модуль?
Сейчас по 7 тысяч они.
ShtAnigga
все нашел.Вопрос исчерпан
Norno
Чтобы датчик показывал истинные значения его требуется периодически калибровать на специальных смесях газов, в противном случае неизбежен дрейф показаний. Не знаю как в этом датчике, но K-22, K-30 (или во всяком случае приборы на их основе) имеют, так называемую ABC калибровку, они принимают за 400 ppm самый свежий воздух которые видели, кажется, за неделю, при этом сдвиг не может превышать 50 ppm. Соответственно такой прибор показыват не концентрацию CO2, а «отношения» к концентрации за окном. Ну а если хочется именно настоящие показания, то без калибровки по смесям не обойтись, причем делать это придется раз полгода-год.
tormozedison
Если к PWM подключить интегрирующую цепочку, получится замечательный аналоговый выход.
Zolg
Суровая получится rc-цепочка. Частота ШИМа-то 1гц.
tormozedison
Электролит на 5000 мкФ ничуть не суров.
Zolg
Электролит в измерительной цепи? Хорошая шутка.
tormozedison
Это смотря какая точность нужна.
alexpp
Спасибо за обзор. Как раз собираю домашнюю метеостанцию на esp — пригодится.
KorDen32
Предложу два варианта, второй предпочтительнее IMHO:
1) подключить к GPIO малины и написать bash/perl/… скрипт
2) подключить к PL2303 и написать bash/perl/… скрипт для того чтобы можно было подключать к роутерам (MR3020, etc), компьютерам и прочему без привязки к платформе
Hellsy22
А чем плох вариант с FT232RL?
KorDen32
Ну или FT232RL, речь о реализации готового скрипте, который будет выводить в ответ человекочитаемые значения (как в примере через ардуину), проверяя CRC-суммы и проч (скажем, предусмотреть возможность указания номера датчика, если есть модели с несколькими датчиками и т.д.).
Т.е. чтобы было что-то типа
```~# ./getco2.sh
785
Возможно, сразу предусмотреть обнаруженные вами проблемы, скажем с ключом --check выводить предупреждения, если значение является заведомо ошибочным (скажем ниже 300) или скачет (например, запрашивая дважды с интервалом в 10-15 сек, если значения разнятся (учитывая ваши примеры ошибок)).
Hellsy22
Не думаю, что стоит оформлять это отдельной статьей, хотя если кому-то нужно, то могу раскрыть тему подробнее.
Получить название порта можно командой: ls /dev/ttyUSB*В конфиге ядра должен быть ключ: CONFIG_USB_SERIAL_FTDI_SIO=m
При подключении девайса в dmesg появится что-то типа:
Чтобы номер не скакал, его можно намертво прибить с помощью udev.
Для работы perl-скрипту нужна библиотека Device::SerialPort, легко ставится через cpan или вручную.
eta4ever
Раз уж проголосовал за свой вариант — закажу и сделаю пока что простейший показометр с маленьким дисплеем (четыре семисегментника) на AVR. А потом уже подумаю, куда его внедрить.
jehy
Четвёртый вариант из голосования (погодная станция с ESP8266) я как раз делал. По SoftwareSerial тоже. Можете в ссылки добавить — по комментариям видно, что много кого интересует, а время на повторное написание имеющегося кода тратить не очень осмысленно. Кстати, опрашиваю раз в 5 секунд — проблем не замечено. У меня, кстати, инициализируется и выдаёт корректные данные после второго обращения, ждать 3 минуты не нужно — а как у вас? И реагирует на изменение обстановки мгновенно. Да, вы проверяли контрольную сумму? И у меня и у другого программиста из моего топика она упорно не сходилась, так что в результате остановились на проверке первых трёх байт.
Hellsy22
Конечно добавлю, хотя результатов голосования это не отменит.
Опрашивать датчик можно хоть сразу, но с холодного старта он будет выдавать ошибочные значения. Однако есть тонкость — если вы датчик просто перезапустили, то ждать не надо.
Насчет контрольной суммы — она у меня сходится, даже в статье пример взят с реальных данных. Если у вас не сошлась, то предположу, что проблема или в unsigned, или в том, что вы не ограничили ее одним байтом. Попробуйте вручную посчитать — там всего-то 8 операций.
KonstantinSoloviov
jehy
Справедливости ради скажу, то не вдвое. MH-Z19 стоит уже сам по себе заметных денег, а ещё нужен корпус, дисплей, ардуина и желательно датчик температуры и влажности. У меня вот получилось за 44$, что на данный момент равно 3224р. Даджетовский сейчас, судя по сайту, стоит 4950 — дороже в полтора раза. "Всего" или "в целых" полтора раза — это уже от ваших потребностей, способностей и достатка зависит.
KonstantinSoloviov
Но далеко не все считают эту цену приемлемой.
В 2500 вписаться легко можно: датчик, attiny2313 (удобный UART, ножек в достатке, кварц не нужен на таких скоростях), индикатор на выбор ЖК или цифровой-LED и по-мелочи — пара конденсаторов.
Пожалуй и на температурный датчик останется )
Если уж считаем копейки, то ардуино здесь лишнее.
jehy
Ардуино нынче меньше 2$ стоит — не дороже датчика температуры, это уже совсем копейки.
Сэкономить значимо можно разве что на корпусе — если руки не кривые, можно из чего угодно собрать.
Hellsy22
Да, как-то так.
MH-Z19 — 26$
Arduini Mini Pro — $1
ESP8266 — 1.5$
LCD 16x2 — 1.5$
DHT22 — 2.5$
BMP180 — 1.5$
Итог: 34$
Плюс расходы на изготовление платы, корпуса и разная мелочь.
Nerten
А зачем здесь Arduino?
Hellsy22
У ESP выводов маловато. Мне удобнее повесить все датчики, экран, кнопки и индикаторы на Arduino, оставив за ESP лишь коммуникацию и управление. На общем потреблении энергии это почти не скажется, место тоже экономить смысла нет.
jehy
Берите arduino compatible плату на ESP — будет одна плата с кучей выходов и интернетом. У меня вот используется wemos d1.
Bobnecat
Я свою метеостанцию как раз на этом датчике собрал, только с ШИМ. По своим впечатлениям скажу что датчику действительно нужно 3 минуты разогрева чтобы начать работать более менее адекватно, и около 1-3 дня работы для повышения чувствительности. Когда его включил в систему первый раз, то был немного разочарован так как в большой комнате по началу он не замечал присутствия 1 человека, но поработав пару дней научился этому. Сейчас даже чувствует присутствие человека находящегося в другой комнате в квартире размером в 100м2. «Чистое» значение воздуха находится в пределах 420 ppm.
iliasam
Тоже экспериментировал с этим датчиком. Повторюсь здесь, а то в обзоре нет информации по потреблению питания.
Напряжение питания должно быть больше 3.6В, если оно будет ниже, то датчик начинает сильно завышать показания.
Потребление тока у датчика импульсное, при напряжении 5В большую часть времени ток 4 мА, но каждые 6 сек потребление возрастает до 100 мА, длительность импульса меньше секунды.
То есть датчик производит измерения раз в 6 секунд, и нет смысла опрашивать его чаще.
Ранее написал маленькую программу — построитель графика CO2 для этого датчика, может, кому нибудь пригодится.
Сложилось ощущение, что датчик начинает работать точней, проработав хотя бы полдня.
Сейчас делаю автономный прибор для измерения CO2, с возможностью строить графики и передавать данные на компьютер при помощи NRF24L01:
CAJAX
В темноте, кстати, через фильтры видно пульсацию диода во время замеров.
Big_Lebowski
Отвлеченный вопрос — А как ESP8266 подключить что угодно с PWM? По-видимому, нужны какие-то дополнительные внешние компоненты, но какие?
Rumlin
В случае "что угодно" может быть понадобится согласовать уровни 3.3/5.
Big_Lebowski
Не, это я понимаю. У ESP есть только GPIO ноги, видимо нужен внешний АЦП, вот я и хочу узнать какой можно использовать.
Rumlin
PWM — это не аналоговый сигнал.
К слову АЦП там есть http://esp8266.ru/forum/threads/tochnost-adc.598/
Big_Lebowski
Спасибо. У меня в голове каша :) Это чтобы выдавать на GPIO ноге определенное напряжение используют PWM, а не наоборот
Rumlin
PWM — ШИМ. Широтно Импульсная Модуляция — Импульсы разной длительности, что отображает картинка выше.
А "определенное напряжение" — этим занимаются ЦАП(DAC) — Цифро-аналоговые преобразователи.
Big_Lebowski
А, я все понял. Это у меня неудачная плата esp8266 на которой не распаян ADC. Вопрос снимается.
Hellsy22
Ничего не нужно. Ловите переходы GPIO HIGH/LOW и засекаете время каждого состояния. Время, пока GPIO был HIGH — это и есть Thigh в формуле, Tlow — соответственно.
Это не лучший вариант, правильно было бы отслеживать изменения через прерывание, но вполне рабочий.
boogiebomzh
Объясните, пожалуйста, как работает этот датчик. Если это он инфракрасный, то, чтобы получить точные значения содержания углекислого газа в воздухе, надо знать еще и влажность, либо как-то осушать воздух, поскольку у водяного пара и углекислого газа спектры поглощения в ИК-диапазоне частично совпадают. В одном из проектов по изучению фотосинтеза, в котором я принимал участие, воздух сперва проходил через холодильник, где конденсировалась лишняя влага, а затем через химический осушитель, и только после этого подавался на инфракрасный газоанализатор для определения содержания углекислого газа.
Hellsy22
Судя по обрывочным сведениям о его младшем брате MH-Z14 и других NDIR-датчиках, он умеет измерять температуру и влажность, корректируя свои показания. MH-Z14 даже возвращал температуру пользователю.
Ваши приготовления, вероятно, были связаны с высокой точностью измерений, тогда как у Z19 точность ± (50ppm + 5% reading value).
3cky
Все-таки непонятно, по документации вход RX 5v tolerant или нет? В статье написано, «5В не рекомендуется», но модуль при этом воткнут в ардуину без каких-либо логических трансляторов.
Hellsy22
Это разница между макетом для проверки и готовой схемой. На макете кратковременное подключение к 5В проблем не выявило, но я не знаю, что будет если подавать пять вольт в течение полугода. Поэтому в конечной схеме я бы использовал резисторный делитель.
Аналогично и с напряжением питания. Сенсор работает даже на 3.3В. Но производитель указывает в качестве напряжения питания 3.6 — 5.5В, причем отдельной строкой подчеркивает важность соблюдения этих рамок.