company_banner

Осциллограф в браузере

  • Tutorial

Отрисовка графиков в реальном времени




Одно время я работал в компании, которая разрабатывала бесконтактные датчики, как на фото. И при установке этих датчиков, надо было правильно сориентировать антенну (белая штука на фото). И выглядело это так: один человек на объекте, где-то в Сибири, на морозе крутит антенну, а другой в Питере, в офисе, не видит того человека, но видит графики на мониторе. И вот они как слепой с глухим пытаются поставить антенну, один по графикам, по телефону говорит, что надо антенну повернуть, а другой пытается понять в какую сторону её крутить. Звучит как бред, правда? Но так и было.

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

Техническое задание


Хоть NDA в той компании я не подписывал, всё же считаю, что разглашать какую-либо информации составляющую коммерческую тайну не имею права. Поэтому постараюсь рассказать в общих чертах.

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

Приёмник подключен к промышленному ПК по интерфейсу RS-485, и уже в нём идёт обсчёт и передача данных по интернету на центральный сервер. В целом, приёмник мог бы делать всё сам, но решили для надёжности реализовать таким образом.


Шкаф приёмного оборудования. ПромПК, блок питания, модем и антенна lte.

Таким образом, у нас есть точка входа: промышленный ПК, на котором стоит Linux. В качестве ПК было много различных вариантов использования: как обычные х86+Ubuntu, так и ARM-роутер на OpenWRT. Поэтому решение должно было быть максимально простым универсальным.
Данные со считывателя получала моя программа, которая работала на ПромПК и сохраняла их в csv-файл разделённых табуляциями, где каждый столбец был сигналом с отдельного канала.
Таким образом, надо было просто сделать WEB-интерфейс, и строить график в реальном времени по этому CSV-файлу. Эпизодически пиная считыватель на новую порцию данных.

Реализация


Основа всего алгоритма CGI-bash скрипт (о боже, CGI на bash), который очень прост:

#!/bin/bash
echo "Content-type: text/html;charset=utf-8"
echo
программа_дающая_данные > /var/www/html/result.dat
echo "true" 
exit 0

Следует помнить о том, что все операции происходят от пользователя и группы www-data:www-data (если для апача). Этот момент у меня попил много крови, вообще помните про свои права и права других пользователей, а также про обязанности.

Вызывая этот CGI-скрипт, я каждый раз получаю свежую порцию данных в файле result.dat, которые можем отобразить. Данные выглядят примерно таким образом:

2019	2010	2160	2006	
2023	2052	2041	1992	
2053	2048	2181	1991	
2019	2054	2147	1968	
2003	1977	2189	1982	
2052	1987	2101	1961	
....

Дальше, мне нужно было этот сsv-файл превратить в json. Сделал это с помощью фреймворка Papa Parse, который парсит csv-файл. Построение графика я реализовал на фреймфорке Chart.js. Там громадное количество примеров на вкус и цвет, каждый сможет подобрать подходящее под свою задачу.

Один важный момент: не забывайте очищать массивы, перед внесением новой порции данных. Иначе начинает уплывать память. В момент отладки, на ночь оставил всё, без очищения. Утром пришёл на работу, а мышка уже не в состоянии ползать.

Соберём всё в кучку


Вроде всё просто, осталось всё собрать в единую кучку. Чтобы вам не тратить времени, этот проект я выложил на github github.com/dlinyj/realtime_graph_on_js

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

#!/usr/bin/env python3
import random
f = open("/var/www/html/result.dat", "w")
for i in range (20):
    f.write("%d\t%d\t%d\t%d\t\n" % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
f.close()

Основа всего — это CGI на bash, о котором писал выше, который вызывает этот питоновский скрипт.

#!/bin/bash
echo "Content-type: text/html;charset=utf-8"
echo
/usr/bin/python3 /usr/lib/cgi-bin/test.py > /dev/null 2&>1
echo "true" 
exit 0

Исходный код всей веб-страницы можно посмотреть вот тут.

Вначале я конфигурирую параметры самого графика. Это всё взято из готовых примеров фреймворка Chart.js.

Обновление графика делается по таймеру. Каждые 2000 мс идёт вызов функции gen_graph(), которая вызывает CGI-скрипт, описанный выше.

var gen_graphUrl = "cgi-bin/gen_graph.sh";
		function gen_graph() {
			$.ajax({
				url: gen_graphUrl,
				success: function(result) {
					parseData();
				}
			});
		}
		parseData();
		var timerId = setInterval(function() {
			gen_graph();
		}, 2000);
		
		function stop_reload () {
			clearInterval(timerId);
		};

Функция parseData() осуществляет парсинг CSV-данных и преобразование из форматт json:

		function parseData() {
			Papa.parse("result.dat", {
				download: true,
				complete: function(results) {
					createGraph(results.data);
				}
			});
		}

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


Заключение


Конечно, весь этот WEB-интерфейс задумывался не только для установки одной антенны. Там было достаточно много другого функционала (прошивка, отладка, добавление коэффициентов), и благодаря этому научился хоть немного программированию на js (хоть понюхал, что это такое). В результате теперь для настройки оборудования нужен только кроссовый кабель и ноутбук. Подключаешь и работаешь в веб-интерфейсе как на обычном роутере. Так же, данный веб-интерфейс доступен по сети, и каждый объект можно отдельно конфигурировать через него, что стало весьма удобно даже людям, далёким от программирования.

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


Ссылки


  1. Репозиторий проекта github.com/dlinyj/realtime_graph_on_js
  2. Фреймворк для построения графиков www.chartjs.org
  3. Фреймворк для парсинга CSV www.papaparse.com



RUVDS.com
VDS/VPS-хостинг. Скидка 10% по коду HABR

Комментарии 28

    +1
    А смотрели в сторону Node-Red?
    Оно умеет брать данные из файла, шлет красоту в браузер по вебсокетам, то есть вполне себе динамически.
    Есть набор UI компонентов, как раз решает задачу отрисовки:
    flows.nodered.org/node/node-red-dashboard
      0
      Всё это более элегантные решения. Но я не знал раньше вообще web-программирования. Плюс, программа, которая сохраняет CSV была изначально.
        0
        для такого небольшого опыта очень хорошо получилось
          0
          Большое спасибо!
      +2
      Осциллограф в браузере

      2015 год. Сетевой осциллограф с контроллера на Mega 2560 в браузере – в реальном времени осциллограммы сетевого напряжения и тока по, если мне не изменяет память, 13-и каналам.

      https://habr.com/ru/post/382177/
        0
        Классное решение, но думаю внедрить было бы слишком проблематично. Так как всё равно надо было бы CSV-парсить, и делать cgi-скрипт перезапуска.
          +2
          Я не в том смысле, что это нужно внедрить, просто увидел надпись «Осциллограф в браузере» и вспомнил о своих экспериментах на эту тему. :)
            0
            А, я скорее сделал призывный заголовок. Конечно это не осциллограф :)
        –1
        del
          +1
          Одно время я работал в компании, которая разрабатывала бесконтактные датчики… а другой в Питере

          Случайно не та ли, что в ТРАНЗАСе располагается?
            0
            Случайно. :)
            0

            А как так была реализована передача данных, что в другом городе видно данные, а локально нет?

              0
              VPN. Я деталей не помню, но там был специализированный софт, который работал вот только так, по ключам. В результате я написал свою программу, которая делала это локально.
              +2
              я вот в своё время пытался что-то похожее сделать,
              мне нужно было что-то типа анализатора спектра в радиочастотном эфире,

              и поэтому меня смущает заголовок статьи «в реальном времени», и потом оказывается что отрисовка 2000 мсек обновление…

              пытался найти библиотеку для отрисовки графика в реальном времени.
              у меня была задача отрисовать со скользящим окном график именно в реальном времени как осциллограф… 1.5мегабит/сек поток валится и надо рисовать на экране примерно 32655 точек на линию (точка uint32), восемь линий на графике…
              в файл оно писалось нормально,
              а вот я уперся именно в отрисовку, я не смог найти библиотеки, которая может так быстро перерисовывать график.

              и вот я так и не смог найти библиотеку для отрисовки. самую быструю которую я нашел, рисует кадр раз в полторы секунды, а мне надо было смотреть в реальном времени… (ms-chart рисует раз в две секунды кадр, на не слабом компе типа i7)

              я пришел к выводу, что надо как-то ускорители графики подключать из игр типа опенЦВ
              если кто может посоветовать для c# или для ява скрипта, какуюто простенькую библиотеку для быстрой отрисовки графиков, я был бы благодарен.
                +1

                Не забывайте, что мозг человека более 15 кадров в секунду уже не...

                  +5
                  да хотябы 10 кадров в секунду получить, а не один кадр в две секунды…
                  +1

                  Посмотрите в сторону webGL, а для простоты можно использовать библиотеку Three.js. Orthography camera для построения 2D графиков.

                    +2

                    Посмотрите на результаты конкурса телеграмм по JS charts. Там реализации выдают 60fps

                    +3
                    какой то эстонский осциллограф
                    можно повысить частоту кадров?
                      0
                      Со стороны js не отвечу, вероятно нет, судя по комментариям. А со стороны железа, оно отдавало данные не чаще раза в секунду.
                      +1
                      снимал данные с датчика ардуинкой, на которой был «websocket-server», который и передавал данные по ws на сервер, который по ws передавал данные в браузер, который и отображал «бегущий график» в «реальном времени» — всё просто, основным тормозом была скорость отдачи данных с датчика. основной особенностью — если физически вынуть сетевой коннектор идущий от адуинки на 10+секунд — и воткнуть обратно — потерь не происходило. сетевой модуль ардуинки имел память и накапливал там не отправленное, при подключении — выплёвывал сохранённое.
                        +1

                        Немного не по теме статьи. Больше касательно датчиков
                        Всегда не понимал, зачем люди так сильно усложняют решение простейшей задачи?
                        Аналогичную задачу (мониторинг температуры шин) можно решить более простыми способами:
                        1) ИК термометр, из готового это различные устройства типа "зной" и им подобных
                        2) Контактные датчики с питанием от трансформаторов на самих шинах
                        3) Бесконтактный датчик с питанием от наводок 50 Гц
                        Зачем этот оверинжиниринг?

                          0
                          1) ИК термометр, из готового это различные устройства типа «зной» и им подобных
                          2) Контактные датчики с питанием от трансформаторов на самих шинах
                          3) Бесконтактный датчик с питанием от наводок 50 Гц
                          Зачем этот оверинжиниринг?

                          1. У каждого тела свой коэффициент излучения. При этом, если будет облучаться солнышком, вы будете получать попугаи. Если покрасить серебрянкой, то будет попугаи. Пролёт. Но справедливости ради, так работает тепловиденье.
                          2. С питанием от трансформатора? На 220 кВ, как вы себе это представляете? Вам ни один энергетик не даст сделать такое питание.
                          3. Все кто пытался делать такие бесконтактные датчики с питанием от наводок, бросали эту затею. Я видел десятки проектов. Крайне низкая надёжность, и всё выгорает при бросках напряжения (молния где-то ударила).

                          Вот на фото полностью пассивные датчики температуры. Просто кусок кремния и антенна. Чудовищная надёжность и простота.
                            +1
                            1. С питанием от трансформатора? На 220 кВ, как вы себе это представляете?

                            Насчёт 220 кВ — надо считать. А насчёт меньших напряжений, где токи повыше, — имеется в виду трансформатор тока на контролируемой шине, от которого запитан измеритель.

                              +1

                              именно

                          0
                          рефреш по аяксу — это немножечко капельку чуть-чуть совсем не реалтайм
                            0
                            Очень классно получилось! Реальная история, когда была пользовательская боль и она решена.
                              0
                              Спасибо!

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое