Перейти к содержимому

Сенсор давления BME680 и способы вычисления IAQ

Добрый день, уважаемый читатель! В этой статье я решил рассказать вам, над какой проблемой я работал в последнее свободное от работы и столярных работ время.

В санузле у меня уже достаточно давно (более года) установлен комбинированный сенсор производства Bosch Sensortec BME680, вот такой:

BME680 - главный герой собственной персоной

 

Этот датчик позволяет измерять сразу четыре параметра окружающей среды:

  1. Давление воздуха
  2. Температуру воздуха
  3. Относительную влажность воздуха
  4. Качество воздуха, то есть его загрязненность

Собственно из-за последней опции я и применил этот датчик, когда проектировал устройство управления вентиляцией санузла. На даче санузел у нас что называется “совмещенный”, поэтому хотелось сделать так, чтобы вентилятор реагировал не только на повышенную влажность после принятия душа или умывания, но и на “плохие запахи”.

С измерением давления, температуры и влажности проблем обычно не возникает, если не учитывать того, что этот датчик (как и все датчики Bosch Sensortec) возвращает данные в “сыром виде” и вам придется пересчитывать данные по достаточно длинным формулам из даташита и предварительно скачанным из датчика же калибровочным коэффициентам. А вот с измерением качества воздуха начинаются проблемы.

 


Физическое устройство BME680

BME680 имеет встроенный металло-оксидный датчик (Metal Oxide Semiconductor) органических летучих соединений (ЛОС). Это датчик резистивного типа, сопротивление поверхности которого зависит от содержания в воздухе ЛОС (летучих органических соединений – этанол, ацетон, изопрен, угарный газ, продукты дыхания и т.д).

К слову, это не единственный сенсор такого типа, в качестве альтернативы можно посмотреть в сторону CCS811, и он даже немного лучше по некоторым показателям.

Недостаток таких сенсоров заключается в необходимости дополнительного разогрева чувствительного элемента с помощью специального нагревателя, температура которого достигает нескольких сотен градусов. В частности в BME680 она составляет около 320 °С. Сопротивление датчика измеряется, оцифровывается 20-битным АЦП, фильтруется и отдается вашему приложению. То есть, по идее, мы бы должны получить значение из следующего диапазона:

Так должны выглядеть результаты измерения качества воздуха "в теории"

А вот дальше начинаются чудеса. Дело в том, что датчик выдает не обещанный рекламой индекс качества воздуха (IAQ), а всего-лишь сопротивление измерительного резистора. В чистом воздухе сопротивление измерительного полупроводникового резистора достаточно велико (несколько сотен килоОм), а при наличии в воздухе органических примесей оно может падать до десятков килоОм. Дальше всё это нужно пересчитать в нужные нам значения.


Получение данных с сенсора

Для начала нужно прочитать все эти данные (в том числе и сопротивление резистора) с сенсора.

Для получения данных с сенсора для ESP32 и ESP-IDF я использовал открытый API от производителя:

GitHub – boschsensortec/BME68x-Sensor-API: Common Sensor API for the BME680 and BME688 sensors

API достаточно несложный, а самое главное – избавляет от необходимости самому вникать калибровочные коэффициенты и формулы преобразования оцифрованных сенсором значений.

Пример функции чтения температуры с датчика из официального API

Хорошо, с получением данных сложностей нет, а как быть с IAQ?

 


Как посчитать IAQ?

Казалось бы – “фигня вопрос” – с помощью банальной функции map() легко преобразовать в нужный вид и диапазон. Да, но проблема в том, что на сопротивление резистора влияют не только собственно летучие органические вещества, но и температура окружающей среды, и самое главное – её влажность!

А что об этом говорит datasheet? А в даташите однозначно сказано – “используете нашу закрытую библиотеку BSEC или BSEC2 и будет вам щасье”, других вариантов производителем просто не предусмотрено. Но “с наскоку” мне не удалось подключить эту библиотеку к своему проекту, поэтому вначале я попытался вычислить IAQ другими способами.

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

  • map(value, fromLow, fromHigh, toLow, toHigh) – просто и тупо пересчитать значение сопротивления из “старого” диапазона fromHigh – fromLow в новый от 0 до 500. Без учета температуры и влажности окружающей среды. Самый простой вариант, который даже гуглить не нужно, и так все знают.
  • map(), но с учетом относительной влажности – добавим поправочный коэффициент на относительную влажность, и будем вносить коррективы в сопротивление резистора. Получилось лучше, но не намного – не учитывается температура.
  • добавим поправку по учетом абсолютной влажности, а потом уже map() – самый точный “самосдельный” вариант расчета, но и тут, увы, не обошлось без недостатков.
  • подключить официальную библиотеку BSEC или BSEC2 к проекту. Здесь у меня возникли сложности с подключением статической библиотеки к проекту ESP-IDF на первоначальном этапе, но в итоге я и её победил.

Все “самодельные” варианты расчета у меня используют map() в том или ином виде. Но тут притаилась одна большая засада – для корректного расчета нужно знать входной диапазон fromLow – fromHigh, а он может медленно дрейфовать в зависимости от каких-то непонятных условий. Это самая большая проблема при таких вычислениях. Сделаешь входной диапазон заведомо шире или уже – и всё, выходные показания уже не верны. Приходилось чуть ли не еженедельно корректировать границы диапазона. Выходной диапазон постоянен – от 0 до 500, с ним сложностей нет.

Вторая проблема – температура и длительность нагрева датчика. Библиотека BSEC, как оказалось, умеет управлять этими параметрами в зависимости от данных, получаемых с датчика. При ручных режимах мы вынуждены поддерживать эти параметры постоянными, что не всегда есть хорошо.

Я долго перебирал варианты расчета на самом устройстве, но в конце концов просто выгрузил данные с датчика в excel и попытался воспроизвести модели расчетов там. Это дало хорошие результаты. Забегая вперед, скажу, что я все-таки подключил BSEC2 к проекту, поэтому для сравнения я приведу графики, дабы можно было сравнить “мои” результаты с образцовыми. И вот что у меня получилось…

 


Вариант 1: простой map()

Используем популярную в Arduino-среде функцию, которая пересчитывает входное значение value из старого диапазона fromLow – fromHigh в новый toLow – toHigh, причем может это делать “с переворотом”, что нам как раз и нужно:

map(value, fromLow, fromHigh, toLow, toHigh)

Какие здесь сложности:

  • Не учитывается зависимость сопротивления резистора от температуры и влажности окружающей среды.
  • Приходится постоянно корректировать границы входного диапазона для пересчета

На верхнем графике красная линия – сопротивление резистора, черная – образец (получено с библиотеки BSEC2), коричневая – простой MAP(). На нижнем графике температура и влажность, измеренные тем же сенсором

Как видно по графикам, выходные результаты очень сильно “плывут” по влажности и не годятся для практического применения.

 


Вариант 2: добавим учет относительной влажности

Этот вариант я нашел где-то в интернете, и почти год пользовался им. Как потом выяснилось, очень даже зря, так как по сравнению с предыдущим этот метод почти ничего не дает. Ссылку дать не могу, так как не могу найти. Код используется примерно такой:

Я использовал поправочный коэффициент hum_ratio = 0,1, с ним результаты получились такие:

Бледно-голубая линия на верхнем графике – этот вариант.

Как видите – по сравнению с коричневой линией не намного лучше


Вариант 3: с учетом абсолютной влажности

Этот метод относительно недавно я нашел здесь: https://github.com/thstielow/raspi-bme680-iaq

Абсолютная влажность оказалась хороша там, что для её расчета используется температура, а это значим, что мы её тоже сможем учитывать в расчетах. Да и экспонента дала свои результаты, видимо. Я не буду переписывать здесь формулы, их можно найти по ссылке выше или в исходниках, ссылка ниже.

Вот такие получились формулы конверсии

Опытным путем прямо в excel подобрал коэффициент влажности hum_ratio = 0.09, с ним у меня получились прекрасные результаты, даже в чем-то лучше, чем у BSEC2:

Ярко-голубая линия – данный вариант

Но и здесь приходится постоянно корректировать границы входного диапазона для пересчета. Это очень напрягает, если честно.

Вы вполне можете использовать этот метод, если не можете использовать BSEC, он дает прекрасные результаты, при условии корректных входных диапазонов.


Скачать готовую библиотечку вы можете здесь: reSensors/reBME68x

В папке data можно найти тот самый excel-файл и поиграться с коэффициентами


 

Подключение BSEC2 к проекту на ESP-IDF

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

1. В CMakeList.txt, который находится в подпапке src проекта, необходимо добавить следующие строки:

Способы вычисления IAQ на BME680

Это укажет системе сборки, что нужно прилинковать библиотеку к проекту. Никакие другие варианты, найденные на форумах, не помогли.

Но это ещё, не всё, оказывается!

2. Нужно указать библиотеку еще и PlatformIO, добавив в platformio.ini строку:

Способы вычисления IAQ на BME680

Без этого добавления всё равно ничего не компилируется.

Но сложности на этом не заканчиваются! Оказывается, с использованием BSEC2 вы не можете произвольно задавать интервал измерения, а только строго по даташиту: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf:

Способы вычисления IAQ на BME680

То есть получать IAQ можно либо каждую секунду, либо один раз в 3 секунды, либо один раз в 300 секунд. Иначе BSEC ругается на неправильный режим измерения (но какие-то результаты все-таки отдает).

Чем хорош этот вариант?

  • Во-первых вам уже не надо заботится о границах “входного” диапазона – библиотека заботится об этом сама.
  • Во-вторых, библиотека так же сама управляет нагревателем, то есть температурой и длительностью.
  • А так же библиотека управляет и режимами изменений – в частности фильтрами, но не всегда корректно. Замечено, при низких значениях оверсемплинга BME680 выдает некорректные данные, поэтому не стоит ставить значение ниже BME68x_OS_X2.

Не буду мучать вас техническими тонкостями работы с библиотекой, вы можете посмотреть исходники здеся или тута: reSensors/reBSEC68x

Результаты работы “в чистом виде”:

 


Практический опыт эксплуатации

Как показал опыт эксплуатации. датчик отлично реагирует на ацетон, зубную пасту, некоторые виды мыла. Даже на некоторые запахи с соседней кухни, иногда. А вот на запах человеческих отходов жизнедеятельности, увы, не так четко как хотелось бы. Хотя реагирует, да, но с какой-то “ленцой”.

Вентилятор после посещения туалета вручную уже практически нет необходимости включать (у меня там вместе с датчиком еще и кнопка с привязанным к нему таймером на 5 минут стоит). Так что опыт положительный.

Хотя по ощущениям, CCS811 показался мне более лучшим и быстрым. Но это тема для отдельной статьи (которой, впрочем, скорее всего уже не будет, так как я планирую написать еще пару “обещаний” и закрыть канал).


Ссылки

  1. BME680 datasheet
  2. BSEC Arduino Library
  3. BSEC2 Arduino Library
  4. BME680 Software and BSEC
  5. API and Bosch Sensortec Environmental Cluster (BSEC2) Software

 

Если вам понравилась статья и вы желаете отблагодарить автора – просто кликните по любому рекламному объявлению.

💠 Полный архив статей вы найдете здесь


Пожалуйста, оцените статью:
[ 5 из 5, всего 1 оценок ]

2 комментария для “Сенсор давления BME680 и способы вычисления IAQ”

  1. Здравствуйте!
    А можно все эти замечательные труды как-нить использовать в Ардуино-IDE совместно с библиотекой Adafruit_BME680.h ??? Ну и для ESP32, разумеется.

    p.s. Перенёс знаменитый проект Алекса Гайвера его метеостанции на Ардуино Нано и BME280 на ESP32, но вместо BME280 использую BME680. Хотелось бы полностью использовать функционал этого датчика!

    1. Сейчас уже точно не вспомню, но в процессе попытки подключения BSEC к своему проекту я встречал массу примеров под Arduino, и ни одного под ESP-IDF. Если не ошибаюсь, на сайте Bosch как раз есть примеры для Arduino

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *