Как сделать термометр в labview
Термокоса под управлением Arduino и LabVIEW
Я работаю в Институте общей физики РАН. Профиль нашей лаборатории — лазерное дистанционное зондирование, конкретно — лидары. Если вы не знаете, что это за звери, можно прочесть, к примеру, в википедии. Лидары иногда ещё называют лазерными радарами. Принципиальное отличие и преимущество лидара в том, что с его помощью можно не только измерять расстояние до объекта зондирования по задержке обратного сигнала, но и получать (по спектру сигнала) информацию о составе и свойствах объекта. К примеру, существуют методы лидарного определения температурного профиля воды по глубине в водоёмах.
Бесконтактные измерения полезны лишь настолько, насколько точны, поэтому для калибровки результатов дистанционных измерений контактными было решено изготовить термокосу — шлейф из нескольких термодатчиков на одной линии.
Железо
Бесконтактный метод с применением лидара позволяет промерять температуру воды на глубину до нескольких метров (это зависит от прозрачности, ясно, что в грязной воде лазерный пучок быстро рассеивается и далеко не проходит), поэтому термокоса небольшая, состоит из пяти термодатчиков, размещённых на кабеле с интервалом 1 м, плюс ещё 4 м кабеля, считая от «верхнего» датчика.
В качестве чувствительных элементов я выбрал цифровые термометры DS18B20 (даташит, 320 кб) в герметичном исполнении, вот такие:
Почему именно такие? Потому что герметичные (улыбка), поставляются уже с кабелем длиной 1 м, дают высокую точность и работают по протоколу 1-Wire, что существенно упрощает коммуникацию с ними.
Вдумчивое изучение даташита дало следующую информацию. Датчики можно подключать двумя способами: обычным, по трём проводам (земля, «плюс» питания и сигнальная шина) и в «паразитном» режиме, когда питание датчик получает с линии данных. «Паразитный» режим ещё более упрощает подключение (всего два провода), но может иногда искажать показания датчика. Любое ухудшение точности нам вредно, да и с платы Arduino, управляющей датчиками, легко доступны 5 вольт, поэтому я решил запитывать датчики обычным способом.
Схема термокосы
Даташит рекомендует использовать подтягивающий резистор номиналом 4.7 кОм, у меня в хозяйстве нашлись только два по 2.2, но на работоспособности прибора это не сказалось.
За управление датчиками и за их связь с внешним миром, т.е., с ПК, отвечает Arduino Nano с контроллером ATMega328P.
Вот так выглядит схема, собранная на макетной плате:
Вот так — конечный вариант после пайки и изолирования:
А это — вся термокоса в сборе (управляющая электроника не изолирована):
Я выбрал Arduino в качестве «мозгов» устройства, во-первых, потому, что эта платформа проста в освоении, а во-вторых, потому что ею можно управлять с ПК из-под LabVIEW (далее для краткости LabVIEW = LV), что немаловажно, так как софт большинства проектов нашей лаборатории написан именно в этой среде, и возможность встраивания простой автоматизированной системы контроля температуры в другие схемы дорого стоит.
Главной фишкой данной задачи является работа с прибором из среды LV, поэтому программирование было решено начать с изучения взаимодействия Arduino и LV. На хабре практически нет информации об этом взаимодействии, поэтому, с вашего позволения, буду описывать всё достаточно подробно.
Начало
Чтобы начать работать с Arduino в LV, нужно прошить ваш контроллер скетчем LIFA_Base.ino, взятым из папки C:/Program Files/National Instruments/LabVIEW [версия]/vi.lib/LabVIEW Interface for Arduino/Firmware/LIFA_Base/. В указанной папке лежит куча файлов — С-шные библиотеки, исходники и два скетча, LabVIEWInterface.ino и LIFA_Base.ino. Первый содержит описания всех функций для работы с Arduino, второй же коротенький и собирает всё воедино для заливки в контроллер.
Вуаля, теперь мы с компьютера посредством LV имеем доступ к большинству возможностей Arduino. Как вы догадываетесь, первое, что я сделал, разобравшись со всем описанным выше, — это поморгал светодиодиком.
Поигрались, теперь за дело.
Протокол 1-Wire и термодатчики DS18B20 существуют уже достаточно давно и широко распространены, поэтому я решил поискать информацию о совместном использовании DS18B20 и Arduino. И почти сразу же наткнулся на подходящий источник, и не где-нибудь, а на официальном форуме LabVIEW (ссылка). Топикстартер имел сходную с моей задачу — считывать показания термодатчика DS18B20 с Arduino из среды LabVIEW. Он занялся поисками и в ролике на YouTube увидел диаграмму LV с присутствующим на ней ВП OneWire Read и спросил у гуру, что это за ВП и где его заиметь. На его просьбу откликнулся автор видео и предоставил исходники и подробную инструкцию, как и что делать.
Предложенный же ВП, в сущности, всего лишь отправляет в указанный ему порт последовательного интерфейса шестнадцатеричное число 1E, дожидается ответа и считывает его:
Всё довольно просто.
Читаем один датчик вручную
Первым делом я отредактировал LIFA_BASE.ino и LabVIEWInterface.ino в соответствии с инструкциями и сделал ВП. Проверил, всё работает, отлично. Потом я сделал кое-что, о чём впоследствии пожалел. В вышеуказанной теме на форуме LV парой сообщений ниже один из участников предложил свою версию ВП, считывающего показания термодатчика, состоящую, по сути, всего из одного подприбора — Send Receive.vi из подпалитры Arduino:
Соблазнившись простотой и не вникнув в подробности, в своих дальнейших экспериментах я ничтоже сумняшеся пользовался этой простенькой версией. Нет-нет, всё хорошо и прекрасно, она корректно работает, однако, тут есть некая тонкость, связанная с различиями между моим сценарием работы цепочки датчик-Arduino-LabVIEW и тем сценарием, для которого сделан ВП с форума. Эта тонкость доставила мне впоследствии некоторое количество головной боли, но об этом чуть позже.
Одной из особенностей датчиков DS18B20 является то, что каждый отдельный экземпляр имеет свой уникальный 8-байтовый адрес (ROM-код), зашитый в него в процессе производства. Это теоретически позволяет вешать на одну 1-Wire линию неограниченно много датчиков. Для реализации такой возможности предусмотрена команда адресации к конкретному датчику.
Чтобы адресоваться, нужно знать адрес. ROM-коды своих датчиков я узнал, воспользовавшись примером DS18x20_Temperature из библиотеки OneWire, и записал их в пять переменных, объявленных в начале программы:
В предложенном варианте OneWire_Read не получает никаких значений. Добавляем в неё параметр — адрес датчика (байтовый массив из 8 элементов):
Перед каждой отправкой какой-либо команды адресуемся к датчику:
и добавляем по варианту на каждый датчик в структуру выбора:
Для испытаний того, что получилось, я сделал свой маленький ВП для единичного опроса одного датчика:
Как видно, выбор датчика для опроса я реализовал через case-структуру на блок-диаграмме.
Для удобства дальнейшего применения я сваял маленький ВПП, как показано на скриншоте ниже, запарился и нарисовал для него няшную иконку и обозвал DS18B20 Read.
Не считая кластеров ресурса Arduino и ошибок, ВПП получает на вход номер датчика для опроса и на выход подаёт показание температуры в виде строки.
Ура! Испытания прошли успешно.
Читаем один датчик в автоматическом режиме
Хорошо, мы теперь умеем опрашивать вручную один датчик. Следующий шаг — циклический опрос одного датчика в автоматическом режиме. Для этого я сделал следующую блок-диаграмму:
Для начала интервал фиксирован, программа раз в секунду опрашивает датчик и после остановки цикла пользователем пишет собранные данные в массив. Для удобства я к каждому показанию температуры добавил временну́ю метку с помощью функции Get Date/Time String.
Включаем, ждём секунд 20, останавливаем… И тут начинается веселье.
Просмотр массива показывает, что температура считывается только первые 5 раз после запуска программы, дальше лишь временны́е метки без показаний температуры:
Я долго не мог понять, в чём же дело — на стороне LV вроде бы ошибки быть не может, блок-диаграмма до безобразия проста, код скетча Arduino тоже корректен, т.к. в режиме единичного ручного опроса работает безотказно. Что ещё может быть? Сама плата Arduino? Понаблюдав за ней, обнаружил следующее. Запускаем программу, дважды мигает светодиод L на пине 13, потом мигает светодиод RX (контроллер принял команду для термодатчика, отправленную ПК), проходит одна секунда (датчик проводит «конвертирование» температуры в байты в своей памяти, ПК ждёт от него ответа), мигает светодиод TX (контроллер получил от датчика байты и отправил их ПК), снова мигает диод RX, снова проходит секунда, снова мигает TX, и так далее по кругу, пока мы не остановим выполнение программы. Так вот, в моей схеме этот калейдоскоп огоньков продолжался первые
5 секунд, а потом контроллер переставал отвечать, беспрерывно мигал диод RX, и программу получалось остановить только кнопкой останова выполнения в интерфейсе LabVIEW.
Вся эта катавасия натолкнула меня на мысль, что где-то что-то не в порядке с таймингом, и я начал копать в этом направлении, изменял время ожидания в ВП, в скетче, анализировал код скетча буквально по строчке, блок-диаграмму ВП по элементику, но ничего не помогало. В конце концов от отчаяния распотрошил Send Receive.vi, потому что неоткуда больше было взяться проблеме. Взгляните на его блок-диаграмму:
Send Receive, как ему и полагается, берёт данные, отправляет их по указанному направлению и принимается ждать. Если в течение 100 миллисекунд ответа не поступает, ждёт ещё 5 миллисекунд, очищает буфер вывода и повторно отправляет данные, всего до 10 таких попыток. Где-то между Send Receive, микроконтроллером и главным ВП в процессе работы возникает и накапливается рассинхрон, и из-за этого к шестой итерации опроса датчика происходит какая-то нестыковка отправляемых и принимаемых команд, которая вешает контроллер.
Как показывает опыт, простое на вид решение — не всегда самое лучшее, поэтому я переделал свой DS18B20 Read.vi:
Признаюсь честно, я не могу точно сказать, в чём же было дело, не хватает глубины понимания взаимодействия микроконтроллера с ПК. Но в результате моих попыток проблема исчезла, и я не стал в неё углубляться.
Читаем все датчики в автоматическом режиме
Как видите, она, за небольшими изменениями, является повторённой 5 раз функцией чтения одного датчика.
Также пришлось немного изменить DS18B20 Read.vi — сделал его универсальным, как для опроса отдельных датчиков (получает на вход номер от 1 до 5), так и для всех сразу (6 на входе). Ещё я изменил число байтов, читаемых из буфера, т.к. при опросе всех датчиков сразу на выходе ВП строка почти в 6 раз длиннее, и увеличил интервал опроса буфера:
Ура, товарищи! Всё работает именно так, как я хотел.
Калибровка
Казалось бы, всё готово, тут можно и успокоиться, но при тестах все пять датчиков, будучи помещёнными в одинаковые условия (стакан с водой), давали несколько разные показания. Поэтому их нужно было прокалибровать.
Для этого понадобились: ртутный термометр с ценой деления 0,01 градус Цельсия, лабораторная стойка с лапкой, стакан, немного льда из морозилки, электрочайник и вода. Импровизированная установка выглядела так:
Прошу прощения за качество фотографий и за беспорядок в лаборатории.
Для нескольких температур были записаны показания ртутного термометра и датчиков, и построены калибровочные кривые для каждого датчика.
В качестве примера — калибровочная кривая для датчика №1.
По параметрам полученных кривых я внёс калибровочные поправки в данные, выдаваемые программой.
Также с помощью этой же «установки» по сравнению показаний датчиков и ртутного термометра была оценена погрешность, даваемая термокосой. Для разных датчиков при разных температурах она незначительно отличается и в среднем составляет 0,08 градусов Цельсия.
Последние штрихи
Интерфейс LIFA для работы с Arduino предоставляет кучу возможностей — работа с LCD-дисплеями, серводвигателями, управление по ИК-каналу и т.д., это всё полезно, но в моём случае совершенно не нужно, и поэтому я довольно радикально урезал содержимое LabVIEWInterface.ino, LIFA_BASE.ino, LabVIEWInterface.h и папки LIFA_Base, убрав оттуда всё лишнее. Листинги тут приводить не буду, если кому-нибудь захочется поглядеть, обращайтесь, все исходники предоставлю с удовольствием.
Для управляющей программы я сделал вот такую фронт-панель:
Платка Arduino для защиты от окружающей среды была упакована в термоусадочную трубку, загерметизированную с торцов:
Итоги
А теперь давайте подумаем. В продаже есть фабричные термокосы, легко гуглится, к примеру, «термокоса ТК-10/10» средней стоимостью 13000 рублей. Вы можете спросить: «А нафига было париться, если существуют аналоги промышленного изготовления сравнимой стоимости, дающие такую же или пренебрежимо худшую точность, заведомо лучше отлаженные, более надёжные и качественно исполненные?» Отвечу, тому несколько причин:
Благодарю всех за внимание! Если возникнут вопросы/предложения/критика, всегда рад выслушать, исходники скетчей и VI-шки предоставлю с удовольствием, как уже писал выше, обращайтесь.
Примеры работ на LabView
Решил создать тему и в ней разместить примеры работ на LabView, которые демонстрируют основные возможности данной среды. Часть этих работ были выполнены мной в период обучения в ВУЗе как лабораторные и курсовые работы.
1. Измерение температуры
В данном примере можно видеть, как значение температуры отображается на графике. Есть возможность выставления верхнего и нижнего предела (лимита). Значения пределов также отображается на графике. В случае, если значение температуры выходит за пределы, происходит индикация этого факта загорающейся лампочкой. Также демонстрируется перевод текущего значения температуры в двоичное представление и индикация этого значения в виде загорающихся лампочек.
Лицевая панель виртуального инструмента (VI):
Следует отметить, что изображенный на диаграмме в качестве источника блок «AS Temp» является другим виртуальным инструментом, вставленным в данный уже в качестве модуля.
Лицевая панель и диаграмма модуля «AS Temp» (в архиве с исходниками файл Digital Thermometr.vi):
Также отмечу, что в учебных целях данные для получения значений температуры берутся не с физического источника (измерительного преобразователя), а по сути, с генератора случайных чисел (встроенного в среду LabView виртуального инструмента DemoVoltageRead.vi).
2. Симуляция логических операций
Есть примеры работ с Local Variable?
Хотелось бы изучить подробнее, но в интернете в основном информация в текстовом виде, а разобраться.
Примеры работ по функциям ПОИСКПОЗ и ИНДЕКС
Вот на этой теме вставляйте свои файлы с примерами по функциям ПОИСКПОЗ и ИНДЕКС
Какие есть примеры работ по предмету «Исследование операций»
Можете подсказать примеры тем, которые не очень сложно реализовать в виде проекта или где можно.
LabView
Hi Ott! Собственно,кто нибудь использует?
3. Организация примитивной передачи данных по компьютерной сети
Виртуальный инструмент №1 (далее – передатчик (во вложении файл AS_SENDER.VI)) осуществляет передачу заданного пользователем числа по указанному адресу в сети с указанного порта по протоколу UDP. Передача осуществляется непрерывно с периодом устанавливаемым пользователем.
Виртуальный инструмент №2 (далее – приемник (во вложении файл AS_RESEIVER.VI)) должен получать в непрерывном режиме данные с определенного UDP порта, на который отправляет данные передатчик.
Приемник отображает полученные данные (числовое значение) на графике, а также:
• сетевой адрес отправителя;
• UDP порт отправителя;
• количество циклов получения данных.
Лицевая панель серверной части (передатчика):
Ниже перечислены визуальные компоненты лицевой панели и их функции:
Start (Vertical Switch) – Запуск и остановка работы передатчика
Receiver IP (String Control) – Позволяет задать IP-адрес получателя (приемника)
Port (Digital Control) – Позволяет задать порт
Sending Number (Knob) – Позволяет задать передаваемое число
Cycle Time (Knob) – Позволяет изменять скорость циклической передачи данных
Лицевая панель клиентской части (приемника):
Ниже перечислены визуальные компоненты лицевой панели и их функции:
Start (Vertical Switch) – Запуск и остановка работы приемника
Sender IP (String Indicator) – Отображает IP-адрес отправителя (передатчика)
Sender Port (Digital Indicator) – Отображает порт отправителя
Number of Cycles (Digital Indicator) – Отображает число циклов приема данных
Received Data (Waveform Chart) – Отображает на графике полученное с передатчика число.
Диаграмма функционирования передатчика:
На данной схеме присутствуют следующие элементы:
Цикл While Loop – Позволяет организовать циклическую передачу данных
Элемент UDP Open – Инициализирует работу протокола UDP
Элемент UDP Write – Передает данные по UDP протоколу
Элемент UDP Close – Завершает передачу данных, используя UDP протокол
Элемент To Decimal – Преобразует число на входе в строку с десятичными символами
Элемент String To IP – Преобразует строку в IP-адрес
Диаграмма функционирования приемника:
На данной схеме присутствуют следующие элементы:
Цикл While Loop – Позволяет организовать циклический прием данных
Элемент UDP Open – Инициализирует работу протокола UDP
Элемент UDP Read – Используется для получения данных по протоколу UDP
Элемент UDP Close – Завершает передачу данных, используя UDP протокол
Элемент IP To String – Преобразует IP-адрес в строку
Элемент From Decimal – Преобразует строку десятичных символов в строку