MoDyz: Стрелочные индикаторы

step962
Offline
Зарегистрирован: 23.05.2011

Основная задача Android-приложения MoDyz  - создание удобного интерфейса для связи с микроконтроллерами по Bluetooth или WiFi. Изначально упор делался на отображении информации и динамическом представлении ее в графическом виде. Эдакая рисовалка с минимумом органов управления. Тема с представлением первой версии  была открыта на форуме где-то в 17-м году.

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

А в начале лета на глаза мне попался набор различных элементов для организации на интернет-страницах приборных панелей. Это и подтолкнуло к разработке 3D-версии стрелочного индикатора для использования в MoDyz.

На данный момент запрограммированы основные свойства стрелочного индикатора. В программном интерфейсе с Arduino пока что имеются лишь три функции:

Создание объекта SSGC
Определение свойств шкалы SSGS
Установка нового значения SSGV

Скриншот (кликабельно) демонстрирует внешний вид индикаторов, создаваемых и управляемых с помощью имеющихся функций интерфейса:

 

b707
Offline
Зарегистрирован: 26.05.2017

код будет? Или это коммерческий продукт?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

step962 пишет:

Основная задача Android-приложения MoDyz 

Да похер - много таких приложений.

Какие данные и в каком формате идут от МК?

step962
Offline
Зарегистрирован: 23.05.2011

b707 пишет:

код будет? Или это коммерческий продукт?

Свежую версию приложения MoDyz и библиотеки MD_Scout можно скачать по этой ссылке.

step962
Offline
Зарегистрирован: 23.05.2011

mykaida пишет:

Какие данные и в каком формате идут от МК?

Общий формат команд, отправляемых микроконтроллером на смартфон/планшет:

#<команда><параметр>,<параметр>,...,<параметр>;

Создание нового стрелочного индикатора - команда SSGC:

#SSGC<id>,<x>,<y>,<r>,<frameType>,<bgColor>,<ptrType>,<ptrColor>;

Здесь id - идентификатор нового индикатора, x,y и r - координаты центра и радиус индикатора, frameType - тип ободка, bgColor - цвет (текстура) циферблата, ptrType и ptrColor - тип и цвет стрелки.

Настройка шкалы стрелочного индикатора - команда SSGS:

#SSGC<id>,<x>,<y>,<r>,<frameType>,<bgColor>,<ptrType>,<ptrColor>;

Здесь id - идентификатор индикатора, созданного ранее командой SSGC, sType - тип шкалы, freeAngle - свободный угол (имеет значение только для одного типа шкалы), vMin и vMax - минимальное и максимальное отображаемые значения.

Установка отображаемого стрелочным индикатором значения - команда SSGV:

#SSGV<id>,<newValue>;

Ну, тут, наверное, все понятно и так: id - идентификатор, newValue- новое значение.

Для ленивых (к ним я отношу и себя) есть библиотека MD_Scout, с помощью которой производится сборка необходимых команд и их отправка Android-устройству. Она, в том числе, содержит и функции управления стрелочным индикатором: 

String ssgCreate(int id, int x, int y, int r, int frameType, int bgColor, int ptrType, int ptrColor);    // SSGC
String ssgDefineScala(int id, int sType, int freeAngle, int vMin, int vMax);    // SSGS
String ssgSetValue(int id, int newVal);    // SSGV

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

step962 пишет:

Свежую версию приложения MoDyz и библиотеки MD_Scout можно скачать по этой ссылке.

Особенно радует наличие подробной документации и большого количества примеров.

step962
Offline
Зарегистрирован: 23.05.2011

Ну, наличие подробной документации и большого количества примеров предполагает наличие большого количества читателей документации и пользователей примеров. Пока что, перефразируя классиков, "узок их круг, страшно далеки они от" вхождения в тему.

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

step962
Offline
Зарегистрирован: 23.05.2011

asam пишет:

Особенно радует наличие подробной документации и большого количества примеров.

Нате вам первый из большого количества примеров.

Вот такой скетч, демонстрирующий работу стрелочных индикаторов (а заодно и кнопок-крутилок) получился у меня за выходные:

#include <SoftwareSerial.h>

// библиотека, автоматизирующая процесс создания управляющих строковых последовательностей
#include <mdwriter.h>
#include <mdsender_bt.h>

SoftwareSerial mySerial(7, 6); // RX, TX
MD_Sender_BT mdScout;
String cmdBuffer,sResponse;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("+--------------== avr_test_MD_BT ==--------------+");
  Serial.println("| testing communication with MoDyz via Bluetooth |");
  Serial.println("+------------------------------------------------+");
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
  sResponse = "";
  cmdBuffer = "";
}

void loop() { // run over and over
  char c;
  if (mySerial.available()) {
    c = (char)mySerial.read();
    Serial.write(c);
    if (c==0x0A || c==0x0D) interpreteCommand();
    else cmdBuffer=cmdBuffer+c;
  }
  if (Serial.available()) {
    mySerial.write((char)Serial.read());
  }
}

void sendString() {
  for(int i=0;i<sResponse.length();i++) {
    mySerial.write(sResponse.charAt(i));
    Serial.write(sResponse.charAt(i));
  }
  mySerial.write('\r'); mySerial.write('\n');
  Serial.write('\r'); Serial.write('\n');
  sResponse = "";
}

void addCmdString(String sCmd) {
  sResponse += sCmd;
  if(sResponse.length()>100) sendString();
}

void drawScene() {
  int x,y,r;
  r = 180;
  sResponse = "";
  addCmdString(mdScout.setDisplayColors(C_BLACK,C_LTGRAY));
  addCmdString(mdScout.setLineColors(C_LTGRAY,C_MAGENTA));
  addCmdString(mdScout.fillRectangleBG(150,10,680,50));
  addCmdString(mdScout.setTextColors(C_RED,C_LTGRAY));
  addCmdString(mdScout.setTextSize(30));
  addCmdString(mdScout.setTextColors(C_BLUE,C_LTGRAY));
  addCmdString(mdScout.outTextC(415,40,"Gauges"));
  addCmdString(mdScout.setLineColors(C_RED,C_MAGENTA));
  addCmdString(mdScout.setLineWidth(4));
  addCmdString(mdScout.drawPoint(415,40-4));
  addCmdString(mdScout.drawPoint(415,40));
  addCmdString(mdScout.setLineWidth(1));
  
  addCmdString(mdScout.fillRectangleBG(150,10+r*2+r/5,680,50+r*2+r/5));
  addCmdString(mdScout.setTextColors(C_RED,C_LTGRAY));
  addCmdString(mdScout.setTextColors(C_RED,C_LTGRAY));
  addCmdString(mdScout.outTextL(320,40+r*2+r/5,"Rotary knobs"));
  addCmdString(mdScout.setLineColors(C_BLUE,C_MAGENTA));
  addCmdString(mdScout.setLineWidth(4));
  addCmdString(mdScout.drawPoint(320,40+r*2+r/5-4));
  addCmdString(mdScout.drawPoint(320,40+r*2+r/5));
  addCmdString(mdScout.setLineWidth(1));

  addCmdString(mdScout.setTextSize(25));
  addCmdString(mdScout.setTextColors(C_YELLOW,C_LTGRAY));
  x = r+r/10;
  y = r+r/10;
  addCmdString(mdScout.ssgCreate(1, x, y, r, 1, 1, 1, 2));
  addCmdString(mdScout.ssgDefineScala(1, 1, 0, 10, 70));
  addCmdString(mdScout.ssgSetValue(1, 40));

  x = x+r*2+r/5;
  addCmdString(mdScout.ssgCreate(2, x, y, r, 2, 2, 2, 3));
  addCmdString(mdScout.ssgDefineScala(2, 2, 0, 0, 140));
  addCmdString(mdScout.ssgSetValue(2, 40));

  addCmdString(mdScout.setTextSize(15));
  addCmdString(mdScout.setTextColors(C_RED,C_LTGRAY));

  x = r+r/10;
  y = y+r*2+r/5;

  addCmdString(mdScout.defineRotaryButton(13, x-r, y-r, r*2, -180, 0, 10, 70));
  x = x+r*2+r/5;
  addCmdString(mdScout.defineRotaryButton(14, x-r, y-r, r*2, -225, 45, 0, 140));
  sendString();
}

void setGaugeValue(int id, int v) {
  Serial.print("set Gauge "); Serial.print(id);
  Serial.print(" to ");       Serial.println(v);
  addCmdString(mdScout.ssgSetValue(id-12,v));
  sendString();
}

void interpreteCommand() {
  if(cmdBuffer.length()==0) return;
  if(cmdBuffer.equals("fun1"))        {Serial.println("Command to draw: "+cmdBuffer); drawScene();}
  else if(cmdBuffer.equals("redrw"))  {Serial.println("Command to redraw: "+cmdBuffer);}
  else if(cmdBuffer.substring(0,5).equals("#FR13")) setGaugeValue(cmdBuffer.substring(3,5).toInt(),cmdBuffer.substring(6,cmdBuffer.length()-1).toInt());
  else if(cmdBuffer.substring(0,5).equals("#FR14")) setGaugeValue(cmdBuffer.substring(3,5).toInt(),cmdBuffer.substring(6,cmdBuffer.length()-1).toInt());
  else {
    Serial.print("Unknown command: <");
    Serial.print(cmdBuffer);
    Serial.println(">");
  }
  cmdBuffer = "";
}

В результате взаимодействия смартфона (или планшета) с установленным на него приложением MoDyz и вышеприведенного скетча получится вот такая картинка (та что справа - слева та картинка, которую выдает мой отладочный планшет с правами администратора aka бога):

Индикаторы во взаимодействии с кнопками-крутилками

     То же - вид со смартфона

Вращая левую крутилку (двигая пальцем в пределах окружности), можно задавать значение для левого стрелочного индикатора, вращая правую - для правого.

В скетче также представлена работа с текстами: вывод текста с выравниванием по центру в верхней строчке и по левому краю - в нижней. Базовые точки помечены маленькими цветными столбиками - красным в верхней строке и синим в нижней.

Исходная картинка строится в функции drawScene() (строки 54-104), а изменения положения стрелок производятся в функции setGaugeValue() (строки 106-111).

В строках 113-125 происходит разбор полученных команд. Первой должна поступить команда "fun1", вызывающая отрисовку представленной на картинке сцены, т.е. выполнение функции drawScene(). Она отправляется со смартфона при нажатии кнопки "Send Drw". Тискать на другие кнопки можно, но реакции это не вызовет никакой (если, конечно, в скетче не запрограммирована обработка той или иной команды, присылаемой при нажатии соответствующей кнопки). На все, кроме кнопки SnSht. Это единственная кнопка, никак не взаимодействующая с микроконтроллером - она делает снимок экрана и сохраняет его в основной памяти в каталоге "Pictures".

Строки 39-47 (sendString()): отправка накопившейся информации в Bluetooth-канал.

Строки 49-52 (addCmdString()): буферизация отправляемых команд с отправкой накопившегося при достижении буферной строкой определенной длины.

Все, расположенное выше строки 39, надеюсь, не требует объяснений - сосредоточимся на строках 54-111?

lilik
Offline
Зарегистрирован: 19.10.2017

step962 пишет:

Так что, малята, немного терпения...

Не совсем ясна ваша генеральная линия. В "мит апп инвенторе" рисуются все " красивые управлялки" для Ардуино и всё. Другое дело библиотека и приложение которые превращают смартфон в мобильный дисплей для ардуино. Потому как цена такого отдельного дисплейчика будет сопоставима с ценой б/у смартфона :-) 

step962
Offline
Зарегистрирован: 23.05.2011

lilik пишет:

Не совсем ясна ваша генеральная линия.

Моя генеральная линия - колебаться с линией партии!!! ;)

lilik пишет:

В "мит апп инвенторе" рисуются все " красивые управлялки" для Ардуино и всё. Другое дело библиотека и приложение которые превращают смартфон в мобильный дисплей для ардуино.

Ну, графическое программирование - это на любителя. Как по мне - так сильно на любителя. А у меня как раз "другое дело" - библиотека и приложение. Вся логика управления дисплеем (а также управления с дисплея) крутится на микроконтроллере. Это позволяет работать с ним не с какого-либо конкретного смартфона (на котором спроектирована панель управления), а с любого, имеющегося под рукой - главное, чтобы на нем MoDyz был установлен. 

lilik пишет:

Потому как цена такого отдельного дисплейчика будет сопоставима с ценой б/у смартфона :-) 

Цена смартфона, используемого в качестве дисплейчика, будет сопоставима с ценой смартфона?!?! Да вы что, неужели?!?!

И вообще - разве это проблема для человека, у которого смартфон и так каждый день оттягивает карман?

-----

Чтобы отвлечься от общих разговоров, подкину немного конкретики, а именно - шпаргалки по типам ободков и стрелок:

Эти шпаргалки относятся к параметрам FrameType и PointerType вышеупомянутой библиотечной функции ssgCreate() и имеют диапазоны допустимых значений, определяющих внешний вид соответственно ободка (0-10) и стрелки (0-15, реализованы пока что варианты с 0 по 10):

GarryC
Offline
Зарегистрирован: 08.08.2016

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

step962
Offline
Зарегистрирован: 23.05.2011

При использовании браузера панель управления тоже сама собой не нарисуется - ему придется подробно объяснять, что и где разместить, как реагировать на информацию, поступающую от МК, какие команды генерить в качестве реакции на те или иные действия с элементами панели управления. И что в результате имеем? Свой протокол, обернутый в HTML-протокол...

lilik
Offline
Зарегистрирован: 19.10.2017

step962 пишет:

Цена смартфона, используемого в качестве дисплейчика, будет сопоставима с ценой смартфона?!?! Да вы что, неужели?!?!

Нет.

Цена графического дисплея на Али с диагональю около 13-14 см и возможностью управления с УНО.

А у вас как раз другое дело - приложение и библиотека, просто линия другая :-)

lilik
Offline
Зарегистрирован: 19.10.2017

Впрочем, я не настаиваю, вам виднее.

step962
Offline
Зарегистрирован: 23.05.2011

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

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

Все, что необходимо сделать - один раз после создания индикатора послать команду активации дисплея. Пересылаемая для этого команда выглядит так:

#SSGD1,1,0;

или в виде функции, определенной в модуле md_scout:

 

mdScout.ssgDefineDisplay(gaugeID,color,decimalPlaces);

Но к делу...

Так выглядят стрелочные индикаторы без дисплеев:

а после двух вызовов функции ssgDefineDisplay

  addCmdString(mdScout.ssgDefineDisplay(1,color1,0));
  addCmdString(mdScout.ssgDefineDisplay(2,color2,2));

приобретают следующий вид:

 

lilik
Offline
Зарегистрирован: 19.10.2017

step962 пишет:

приобретают следующий вид:

 

Ещё так можно делать, чтоб красоту стрелок не перебивать.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

lilik пишет:

step962 пишет:

приобретают следующий вид:

 

Ещё так можно делать, чтоб красоту стрелок не перебивать.

интересное решение, я за!