[V628] Woltomierz panelowy Meratronik V628 - akwizycja i obróbka danych pomiarowych | cz.4

Kącik dla elektroniki retro - układy, urządzenia, podzespoły, literatura itp.
Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

[V628] Woltomierz panelowy Meratronik V628 - akwizycja i obróbka danych pomiarowych | cz.4

Postautor: tasza » piątek 23 lut 2018, 23:23

#slowanawiatr

♬ ☘ Moja muzyka do majstrowania ♬ ♬ ♬ ☘
♫ ♩ ♪ Monolith ⚡ ☘ ⚡ Voyager ♪ ♩ ♫
https://youtu.be/nDrjtx6Fhq8



No proszę, jak to liczący sobie latek czterdzieści neonowy mierniczek potrafi zaabsorbować, tematów wymyślać można sobie w bród. A mając już podrutowany interface do komputera PC nie sposób pominąć tematyki prostej akwizycji danych oraz późniejszej obróbki tego, co pracowicie udało się zebrać. Instalacja moja wprawdzie zabawowo zorientowana, niemniej jednak problemy już bardziej na serio, choćby obróbka zabrudzonych danych i ich w miarę sensowna prezentacja, no to zapraszam!

Girls go code

Ardu

No to troszkę oprogramowania najpierw, ponieważ bez stosownego wsparcia softwarowego zabawy nie będzie. Aplikacja na Arduino została nieco zmodyfikowana, pracuje teraz w trybie konwersacyjnym (request-response), czyli jeżeli dostanie polecenie to wtedy odsyła wynik przetwarzania, to proste. Ramka danych zawiera licznik inkrementowany w każdym przerwaniu od miernika, to pozwala stwierdzić, czy kolejno odsyłane komunikaty są świeżymi danymi, czy sucharami z cache. Ramka zawiera znacznik przekroczenia zakresu flagowany jako O (over), gdy nie występuje i odbywają się normalne pomiary - Ardu wysyła tam M (measure). Potem lecą cztery nibble zawartości wyświetlacza, poprzedzone polaryzacją +/-.
I w sumie to tyle.

Pętla główna, interpretująca póki co jedno polecenie:

v628link.ino pisze:

Kod: Zaznacz cały

void loop() {   
  char c = 0x00;
  String rxBuff = "";
  while ( 1 )  {
    if ( Serial.available() > 0 ) {
      c = Serial.read();
      if ( c == '\n' ) { // process on enter
          rxBuff.trim();
          processCommand ( rxBuff );
          rxBuff = "";
      }
      else {
          rxBuff += c;     
          if ( rxBuff.length() > 8 ) {
            rxBuff = ""; // bad way :-(
          }
      }
    }//if
  }//while
}


Obsługa polecenia READ:

v628link.ino pisze:

Kod: Zaznacz cały

void processCommand ( String cmd ) {
  char t[ 32 ];
  unsigned short cntr, value; 
  if ( cmd == "READ" ) {
      noInterrupts(); 
      value = ushLastMeterState;
      cntr = ushMeasureCounter;
      interrupts(); 
      // response frame
      // nnnn|N/O|+abcd\n
      sprintf ( t, "%04x|%c|%c%04x",
                    cntr,
                    value & (1 << 14) ? 'O' : 'M',                     
                    value & (1 << 15) ? '-' : '+',
                    value & 0x2FFF
                );       
      Serial.println( t );                 
  }     
}


Cały projekt w v628daq.zip/v628link/v628link.ino


Pececik

Oprogramowanie V628daq powstało jakiś czas temu na potrzeby artykułu o V543, pod tę prezentację przerobiłam tylko parę detali, ponieważ i wyświetlacz małego Meratronika uboższy i funkcji V628 ma jakby mniej. Programik jest tragicznie wręcz prosty - wysyła co kilkaset milisekund polecenie READ do Ardu w odpowiedzi dostając zachomikowane w nim dane o stanie miernika. Odebrana ramka danych służy do odświeżenia zawartości wyświetlacza. Z interwałem zdefiniowanym via combo `save period` programik zapisuje nowe rekordy oraz ich znacznik czasu do pliku-logu, który zakładany jest na nowo przy każdym uruchomieniu aplikacji. Nowe rekordy dodawane są w trybie append, więc ewentualny pad programiku nie zniszczy nam zgromadzonych danych. Całość została napisana w FPC/Lazarus, tak mi było najwygodniej, do zbudowania projektu potrzeba industrialnych kontrolek i komponentu do portu szeregowego, instalacja tu: :arrow: industrialne kontrolki a projekt dla Lazarus IDE w v628daq.zip/v628daq

Archiwum z kodami (a także z próbkami danych i skryptami): :arrow: v628daq.zip

Akwizytorom mówimy...

... udanych wieczornych pomiarów i aby do rana! A instalacja testowa, czyli melanż interfejsu na CD4021, Ardu oraz odejmowaczki napięć na AD708 przedstawia fotografia poniżej.

Obrazek

Programik w działaniu trudno jest uchwycić wespół ze zgodnym odczytem z V628, najmniej kłopotliwy jest tu V640 z racji wrodzonego spokoju - oto odczyty zaokiennego chłodu, no cóż, coraz zimniej jakby:

Obrazek
Obrazek
Obrazek

No i tak sobie to wszystko ładnie działało, dane zrzucały sie do plików, w folderze /data jest ich kilka, ponieważ aplikacja była uruchamiana parę razy. Jeden z plików jest logiem z prawie całej nocy i sporej części poranka, dobry materiał do dalszych zabaw i testów.

Dane, dużo, mnóstwo danych

Przyjęte podejście do magazynowania danych (periodyczny append na logu o unikalnej nazwie per uruchomienie) ma kilka konsekwencji. Po pierwsze, w przypadku wykrycia, że coś idzie nie tak - przerywając program kończymy aktualny zestaw danych. Po drugie - edycja zawartości logu poza plecami programu v628daq choć teoretycznie możliwa jest raczej ryzykowna. Ale za to pliczek z coraz to nowszą zawartością możemy sobie oglądać i przetwarzać różnymi narzędziami i pozyskiwać interesujące nas dane, choć zbiór na dysku ciągle żyje.

awk

Przedstawię może próbkę z logu robioną przez V628daq, będzie łatwiej opowiadać, poniżej pierwsze testy z LM35:

20180222_185815_v628_readings.txt pisze:

Kod: Zaznacz cały

2018-02-22 18:58:20|0011|M|+2208
2018-02-22 18:58:25|002a|M|+2209
2018-02-22 18:58:30|0043|M|+2208
2018-02-22 18:58:35|005b|M|+2207
2018-02-22 18:58:40|0074|M|+2206
2018-02-22 18:58:45|008d|M|+2207


A to fragment poranny z największego zrzutu, no prawie minus sześć, brrrr.

20180222_220211_v628_readings.txt pisze:

Kod: Zaznacz cały

2018-02-23 05:05:15|e15e|M|-0580
2018-02-23 05:05:20|e176|M|-0579
2018-02-23 05:05:25|e18e|M|-0580
2018-02-23 05:05:30|e1a7|M|-0580
2018-02-23 05:05:35|e1bf|M|-0581
2018-02-23 05:05:40|e1d7|M|-0580
2018-02-23 05:05:45|e1f0|M|-0580


No, wygląda to strasznie technicznie, spróbujemy zatem pozyskać z takich danych informacje w ludzkim formacie, pomocne będzie arcysprytne narządko o nazwie `awk`. Tutoriali do awk jest cała masa, to przecież jeden z podstawowych programików w Unix/Linux, ja akurat zerkałam w te materiały (no i oczywiście radosne pytania do Google typu `awk previous next row`):
:arrow: http://www.grymoire.com/Unix/Awk.html
:arrow: https://www.tutorialspoint.com/awk/awk_ ... rators.htm

Najpierw selekcja kolumn z logu, interesuje nas znacznik czasu, zamiast w napięcie trafiłam w znacznik przekroczenia, no każdemu się może zdarzyć:

Obrazek

Kod: Zaznacz cały

awk -F '|' '{ print $1, $3}' 20180222_192400_v628_readings.txt


Stanowczo jednak kolumna $4 będzie lepszym wyborem, przy okazji spróbujemy przerobić prostymi operacjami matematycznymi surową wartość na coś, co przypomina temperaturę:

Obrazek

Kod: Zaznacz cały

awk -F '|' '{ print $1, $4/100}' 20180222_192400_v628_readings.txt


Warto potrenować formatowanie wyników czyli znana i lubiana funkcja printf()

Obrazek

Kod: Zaznacz cały

awk -F '|' '{ printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt


Tu w zasadzie wszystko byłoby fajnie, ale zostawienie tylko jednego miejsca po przecinku zabrało całą dynamikę dalszemu przetwarzaniu, no za mało się dzieje na ekranie po prostu, więc choć sens w tym średni, do rysowanek później będę korzystała z `%2.2f`

To była selekcja danych w pionie, kolumnami, zabieramy sobie to co nam aktualnie z rekordu potrzeba. Jak wspominałam log rozszerzany jest o ustawiony w pascalowej aplikacji interwał czasowy. No ale przecież możemy chcieć dane z określonych momentów, powybieramy sobie zatem pomiary ze wskazanych periodycznych punktów na osi czasu bazując na analizie znacznika w kolumnie $1, to selekcja pozioma.

Przykładowo co 30sek:

Obrazek

Kod: Zaznacz cały

awk -F '|' '(index($0,":00|") !=0)||(index($0,":30|") !=0) { printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt



Pełne minuty:

Obrazek

Kod: Zaznacz cały

awk -F '|' ' index($0,":00|") !=0 { printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt


A może co 5 minut, w końcu temperatura tak wolnozmienna jest, że niewiele stracimy:

Obrazek

Kod: Zaznacz cały

awk -F '|' ' (index($0,"0:00|") !=0) || (index($0,"5:00|")) !=0 { printf "%s %2.1f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt


A za oknem zrobiła się z tego wszystkiego nocka i jej mroźne -4, log z pomiarów powoli aczkolwiek uparcie przyrasta.

Obrazek

gnuplot

Jak to było z tym obrazkiem? Że wart tysiąca słów?
No może i tak, szczególnie gdy potrzebujemy przedstawić zmiany jakiejś wielkości w dziedzinie innej, najczęściej na osi czasu. W Linux jest genialny wręcz programik `gnuplot`, z poziomu konsoli możemy sobie rysować ze zgromadzonych danych naprawdę cudne wykresiki. Ja gnuplot dopiero poznaje, zerkam w te strony i linki dookoła:
:arrow: https://www.techrepublic.com/blog/linux ... h-gnuplot/
:arrow: http://gnuplot.sourceforge.net/docs_4.2/node76.html
:arrow: https://alvinalexander.com/technology/g ... s-examples
:arrow: http://www.gnuplotting.org/plotting-data/

Póki co to szkice niezbyt urodziwe, ale nawet takie pozwalają zauważyć sprawy, których w kolejnych linijkach cyferek jakoś na pierwszy rzut oka nie widać, o na przykład:

Obrazek

To trwały ślad po próbach doregulowania offsetu -500mV przy działającej instalacji, coś przez chwilę nie stykło, ale Ardu jednak nie zawisło i nie zerwało połączenia z PC - stąd ładnie widać jakie były wartości przez regulacją, potem bhhrrr, potem już po regulacji i przepraszamy za usterki.


Jak się robi wykresiki? Ano podajemy programikowi gnuplot skrypt do wykonania, tam zawarte sa wszelkie informacje o ustawieniach rysowania, osiach skalach i sposobie analizy danych źródłowych. Ja to sobie pozamykałam w małe skrypty, wszystko w folderze /data, a teraz tylko taki nieco ogólny przykład:

live.sh pisze:

Kod: Zaznacz cały

gnuplot live.gnu


live.gnu pisze:

Kod: Zaznacz cały

set grid
set timefmt '%Y-%m-%d %H:%M:%S'
set xdata time
set xtics 3600
set ytics 1
set yrange [-10:10]
plot "<./prepareDataCorr.sh" using 1:3 with lines
pause 2
reread


I w skrócie co do czego:
- włączamy siatkę
- ustawiamy format znacznika czasu, ponieważ jego wartości będą na osi odciętych
- mówimy że na osi odciętych jest czas
- podziałkę co jedną godzinę na przykład (wartości w sekundach)
- podziałkę dla osi rzędnych
- zakres osi rzędnych
- wskazujemy źródło wartości i które kolumny z niego nas interesują, łączymy liniami
- czekamy dwie sekundy
- odmalowujemy rysowankę

A z tym odmalowywaniem po pause sztuczka jest taka, że jeżeli dane do rysowania wykresu są generowane przez skrypt wskazany przez 'plot <', to skrypt zostanie ponownie wykonany, dostarczając na przykład odświeżonych wartości.


Poniżej prosty przebieg zmian temperatury z autoskalowaniem i różnymi wartościami xtics oraz różną długością serii danych, widać że ma ADHD

Obrazek
Obrazek
Obrazek
Obrazek

Ustawiamy zakres na osi Y:

Obrazek

Zmieniamy znaczniki osi Y na nieco gęstsze:

Obrazek

I tak się można bawić do woli czytając dokumentację i fora, ale zrobił poranek ze swoimi prawie -6°C

Obrazek
Obrazek

potem coraz cieplej

Obrazek


Dirty dancing data

Jeżeli zadamy sobie trud przejrzenia logu z pliku 20180222_220211_v628_readings.txt to znajdziemy tam na przykład takie dziwadła:

20180222_220211_v628_readings.txt pisze:

Kod: Zaznacz cały

2018-02-23 05:22:40|f537|M|-0592
2018-02-23 05:22:45|f54f|M|-0592
2018-02-23 05:22:50|f568|M|+0592
2018-02-23 05:22:55|f580|M|-0593
2018-02-23 05:23:00|f599|M|+0593
2018-02-23 05:23:05|f5b1|M|-0594
2018-02-23 05:23:10|f5c9|M|-0596


Niektóre rekordy mają odwróconą polaryzację! Takie szpilki, w zupełnie przypadkowych momentach. Co do wartości bezwzględnej pomiar jest w porządku, dostał tylko niewłaściwy znak. Na wyświetlaczu V628 nie udało mi się tego zaobserwować, obstawiam zatem jakiś problem natury kontaktowej w interfejsie, w końcu był dwa razy lutowany. Cokolwiek jednak tam się nie stało, fakt jest taki, że mamy w pliku nie do końca właściwe rekordy i one nam skutecznie psuja malowanki:

Obrazek
Obrazek

No i tu dochodzimy do zagadnienia - jak oczyścić strumień danych z takich śmiećków. Pierwsza myśl, nieco naiwna w sumie to: skoro mamy ciągle na minusie, to może w skrypcie wybierającym dane po prostu odrzucać te dodatnie szpilki? O tak przykładowo:

prepareData.sh pisze:

Kod: Zaznacz cały

awk -F '|' '((index($0,":00|") !=0)||(index($0,":30|") !=0) && ($4 < 0))  { printf "%s %2.2f\n", $1, $4/100 }' 20180222_192400_v628_readings.txt


I zasadniczo wszystko byłoby dobrze, ale do chwili gdy zaczęło grzać słonko, które zawitawszy na parapet z MCP9700 zrobiło mi tam ostrowieckie Hawaje, a skrypt konsekwentnie odrzucił całość pomiarów powyżej zera. Czyli, że słońce szkodzi nie tylko wampirom.

Obrazek
Obrazek

W ramach walki z tymi szpilkami powstała kolejna wersja skryptu wybierającego dane:

prepareData.sh pisze:

Kod: Zaznacz cały

awk '\
function abs(v) {return v < 0 ? -v : v} \
BEGIN{ FS="|"; s1=1; s2=1; } \
((index($0,":00|") !=0)||(index($0,":30|") !=0) ) { \
val=$4/100; \
if (( s1 != $4/abs($4) ) && ( s1 == s2 ) ) { \
  val = val * s2; \
} \
printf "%s %2.2f\n", $1, val; \
s2=s1; \
s1=$4/abs($4); \
 } ' 20180222_220211_v628_readings.txt


Wymyśliłam sobie tak, że zapamiętuje dwie ostatnie polaryzacje przebiegu, co pozwala mi skorygować tę niby błedną na podstawie poprzednich w przypadku pojawienia się takiej właśnie szpilki. Wynik działania jest tak na 3+, jednak algorytm nie jest stuprocentowo szczelny i jednego śmiećka mi przepuścił.

Obrazek

Tak ogólnie, to myślę, że takie surowe dane z pomiarów trzeba przed rysowaniem przepuścić przez jakieś dedykowane narzędzie, które porządnie matematycznie obrobi cały towar, wyeliminuje przypadkowe wpisy, pouśrednia i dostawi brakujące sample (o ile potrzeba) etc. Bo samoróbkami jak powyżej można łatać ad-hoc, a i tak pewnie znajdzie się przypadek, który nas zaskoczy...

Na koniec nocne kino - DAQ bardzej na żywo:

https://youtu.be/cHODKVLV3bE

oraz pomiary w przyspieszonym tempie (z pomijaniem klatek)

https://youtu.be/9boMKd_0xlk

A po całonocnej galopadzie mierniczkowi tak ogólnie to jeden z driverów 74141 zaniemógł i teraz mam na pozycji setek 9 w tle, no takie życie. To jest sprawa uszkodzenia wyjścia kostki, daje czterysta mV spadku napięcia przy pomiarze ciągłości obwodu i to w obie strony, inne wyjścia - są przerwą. Kostki '141 akurat mam, w wolnej chwili trzeba będzie przelutować układ, bo mi śmiesznie na zdjęciach wygląda, ale to kiedyś.

Obrazek
Obrazek
Ostatnio zmieniony niedziela 25 lut 2018, 22:29 przez tasza, łącznie zmieniany 2 razy.
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
inż.wielki
User
User
Posty: 307
Rejestracja: niedziela 20 gru 2015, 23:11

Re: [V628][awk][gnuplot] Woltomierz panelowy Meratronik V628 - akwizycja i obróbka danych pomiarowych | cz.4

Postautor: inż.wielki » piątek 23 lut 2018, 23:34

Fajny projekt. Ja do wyświetlania wykresów używam kst2. Mega dużo możliwości, dowolna ilość wykresów i tryb pracy live z nowymi danymi

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

[V628] Woltomierz panelowy Meratronik V628 - akwizycja i obróbka danych pomiarowych | cz.4

Postautor: tasza » niedziela 25 lut 2018, 22:43

♬ ☘ Moja muzyka do majstrowania ♬ ♬ ♬ ☘
♫ ♩ ♪ Monolith ⚡ ☘ ⚡ Nexus ♪ ♩ ♫
https://youtu.be/phYI73fI0-I


Wszystko na raz

Czyli jak łatwo zgadnąć zabawka ewoluowała do systemu akwizycji wielokanałowej. Nie było to zbyt trudne w realizacji, w końcu kostka MAC24A czyli śliczny, ceramiczny multiplekser analogowy była już ćwiczona przy okazji Motorolki. Drobna nowość to pomiar (no, to zbyt wiele powiedziane) natężenia światła, zrealizowany na bazie fotorezystora, który znalazł się podczas sortowania rezystorów. Powstało zatem pokraczne coś, czego schemat widnieje na rysunku poniżej:

Obrazek

Najpierw rozbiórka wczorajszej konstrukcji.
Obrazek

I krok po kroczku, drucik po druciku powstaje nowy byt.
Obrazek
Obrazek
Obrazek

Fotoelement w pełnej krasie, mam nadzieje, że widać...
Obrazek
Obrazek

Testy instalacji
Obrazek
Obrazek

Wynikła przy okazji konieczność zmiany wiatraczka na i cichszy i wydajniejszy, nowy pochodzi ze śmietnikowej zdobyczy, o której wspominałam kiedyś na fb.

Obrazek

Śmigiełko wprawdzie na 12V, ale zasilane nawet z 5V żwawo i cichutko się kręcąc wymusza cyrkulację w pudełku V628, zamiast mocno ciepłe jest aktualnie letnie i super!

Multi-Ardu-DAQ

Czyli zmieniamy oprogramowanie pokładowe Arduino, ponieważ trzeba teraz umieć obsługiwać cztery kanały pomiarowe. Efektywnie trzy, czwarty stale na masie, ponieważ zabrakło mi pomysłu, co fajnego można na szybko mierzyć. Pojawienie się multipleksera w torze pomiarowym wykluło pewien problem, a mianowicie - nie można przecież przełączać wejścia miernika gdy ten właśnie pracowicie mierzy. Zatem przyjęłam tak, że po odmeldowaniu gotowości wyniku dane są zabierane do tabelki i kanał jest przełączany, choć wtedy trwa pomiar. Specjalny marker nakazuje zignorować ten pomiar jako potencjalnie od czapki i zebrać prawdziwe dane przy następnym obiegu. I tak w kółko, cyklicznie dla czterech kanałów. To jedno z wielu możliwych rozwiązań, pewnie można inaczej, a dla mnie najważniejsze, że na polecenie READ sterownik odpowiada ramką danych z czterema wartościami pomiarowymi. Cały kod dla Ardu poniżej:

v628link.ino pisze:

Kod: Zaznacz cały


#define LINE_READY  2
#define LINE_DATA   3
#define LINE_LOAD   4
#define LINE_CLK    5
#define LINE_START  6

#define LINE_SELECT_A0 7
#define LINE_SELECT_A1 8


#define SKIP  100
#define READY 200

volatile int phase = SKIP;
volatile unsigned short ushLastMeterState[4] = { 0, 0, 0, 0 };
volatile char currentChannel = 0;
unsigned short ushMeasureCounter = 0;



void setup() { 
  Serial.begin( 9600 );
  pinMode( LINE_DATA, INPUT );     
  pinMode( LINE_READY, INPUT );
  // H - parallel-transparent, L-lock data, serial   
  pinMode( LINE_LOAD, OUTPUT );  digitalWrite( LINE_LOAD, HIGH ); 
  pinMode( LINE_CLK, OUTPUT );   digitalWrite( LINE_CLK, LOW );   // L by default
  pinMode( LINE_START, OUTPUT ); digitalWrite( LINE_START, HIGH ); // unused

  pinMode( LINE_SELECT_A0, OUTPUT );  digitalWrite( LINE_SELECT_A0, LOW ); 
  pinMode( LINE_SELECT_A1, OUTPUT );  digitalWrite( LINE_SELECT_A1, LOW );   
 
  attachInterrupt( digitalPinToInterrupt( LINE_READY ), OnMeterDataReady, RISING );
}

void SetMuxAddr ( unsigned char c ) {
  digitalWrite( LINE_SELECT_A0, c & 0x01 );
  digitalWrite( LINE_SELECT_A1, c & 0x02 );
}

void OnMeterDataReady (void) {
    if ( phase == SKIP ) {
      phase = READY;
      return;
    }
    else {
      phase = SKIP;
    }
    ushLastMeterState[ currentChannel ] = readV628rawData();
    ushMeasureCounter++;
    currentChannel++;
    if ( currentChannel > 3 ) {
      currentChannel = 0;
    }
    SetMuxAddr ( currentChannel );
   
}

unsigned short readV628rawData( void ) {
  unsigned short rawFrame = 0;
  int n; 
  digitalWrite( LINE_LOAD, LOW ); // down L and shift serial data
  for ( n = 15; n >= 0; n-- )  {
    if ( digitalRead( LINE_DATA ) ) {
       rawFrame |= ( (unsigned short)1 << n );
    }     
    digitalWrite( LINE_CLK, HIGH);       
    digitalWrite( LINE_CLK, LOW);
  } // for       
  digitalWrite( LINE_LOAD, HIGH ); // release register to transparent
  return rawFrame;
}

void processCommand ( String cmd ) {
  char txBuff[128] = "";
  char s[20];
  unsigned short cntr, value[ 4 ], v; 
  int n;
  if ( cmd == "READ" ) {
      noInterrupts(); 
      memcpy ( value, ushLastMeterState, sizeof( value ) );
      cntr = ushMeasureCounter;
      interrupts(); 
      sprintf ( s, "%04x|", cntr ); 
      strcat ( txBuff, s );
      for (n = 0; n < 4; n++ ) {
         v = value [n];
         sprintf ( s, "%c:%c%04x",         
            v & (1 << 14) ? 'O' : 'M',                     
            v & (1 << 15) ? '-' : '+',
            v & 0x3FFF                 
         );       
         strcat ( txBuff, s );
         if ( n != 3 ) {
            strcat ( txBuff, "|" );         
         }
      } //for
      Serial.println( txBuff );                 
  }     
}

void loop() {   
  char c = 0x00;
  String rxBuff = "";
  while ( 1 )  {
    if ( Serial.available() > 0 ) {
      c = Serial.read();
      if ( c == '\n' ) { // process on enter
          rxBuff.trim();
          processCommand ( rxBuff );
          rxBuff = "";
      }
      else {
          rxBuff += c;     
          if ( rxBuff.length() > 8 ) {
            rxBuff = ""; // bad way :-(
          }
      }
    }//if
  }//while
}



Gepard z rozczworzeniem jaźni

Oczywiście analogiczne zmiany musiałam nanieść w Lazarus IDE na aplikację okienkową na PC, sporo przestawianek na ekranie było, głównie natury wizualnej. Przy okazji wymyśliłam sobie tak, że jak pomiar jest ok i przylatuje z V628 znacznik M to jest dostawiane serduszko, a jak O czyli Over to czacha, taki gadżet. Format pliku z logiem pomiarowym niewiele się zmienił, ale o tym za chwilkę.

W sumie najbardziej dotknięta część kodu - obróbka ramki z Ardu i dystrybucja danych na cztery zestawy kontrolek ekranowych:

main.pas pisze:

Kod: Zaznacz cały

procedure TMainForm.ProcessV628Data ( rawFrame : string );
var
    sl : TStringList;
    disp,stat : array [1..4] of TLabel;
    i : integer;
begin
     disp [1] := self.LabelDisplay1; disp [2] := self.LabelDisplay2;
     disp [3] := self.LabelDisplay3; disp [4] := self.LabelDisplay4;
     stat [1] := self.LabelStatus1;  stat [2] := self.LabelStatus2;
     stat [3] := self.LabelStatus3;  stat [4] := self.LabelStatus4;
     self.EditRawFrame.Text := rawFrame;
     sl := TStringList.Create;
     try
       sl.Clear;
       sl.StrictDelimiter := true;
       sl.Delimiter := '|';
       sl.DelimitedText := rawFrame;
       if sl.Count = 5 then
        begin
           for i := 1 to 4 do
           begin
              disp [i].Caption := Copy (sl [i], 3, 5);
              if Copy (sl [i], 1, 1) = 'O' then
                 stat[i].Caption := '☠'
              else
                stat[i].Caption := '♡';
           end;
       end;
     finally
        sl.Free;
     end;
end;


Wersja mocno rozwojowa.
Obrazek

Bliższa finałowi.
Obrazek

No i w działaniu:
Obrazek

Bardziej na żywo aplikacja pracuje tak, widać w pewnym momencie nagły Over na kanale 3 - to konsekwencje oświetlenia latarką fotoelementu.

https://youtu.be/MruhtgHNuDk

Obróbka danych pomiarowych

Po pierwsze, format logu, maleńka zmiana:

20180225_161852_v628_readings.txt pisze:

Kod: Zaznacz cały

2018-02-25 16:59:10|1716|M:-0357|M:+2279|M:+0370|M:+0005
2018-02-25 16:59:15|1722|M:-0358|M:+2283|M:+0358|M:+0005
2018-02-25 16:59:20|172e|M:-0359|M:+2283|M:+0375|M:+0005
2018-02-25 16:59:25|173b|M:-0360|M:+2281|M:+0367|M:+0005


I juz widać, że należy umieć zauważać znacznik M/O, choćby po to, aby go póki co zignorować, potem powstaje zagadnienie wyrysowania na jednej kartce trzech wykresów - dwóch temperatur i poziomu oświetlenia. Przydały się takie stronki:
:arrow: http://thomas-cokelaer.info/blog/2011/0 ... substring/
:arrow: https://stackoverflow.com/questions/252 ... in-gnuplot
:arrow: http://www.gnuplotting.org/tag/multiplot/

Samo wybieranie danych realizowane jest przez zmodyfikowany skrypcik, kod poniżej:

multiData.sh pisze:

Kod: Zaznacz cały

awk '\
function abs(v) {return v < 0 ? -v : v} \
BEGIN{ FS="|"; } \
((index($0,":00|") !=0)||(index($0,":30|") !=0) ) { \
outdoor=-1*abs(substr( $3, 3 )/100); \
indoor=abs(substr( $4, 3 )/100); \
light=(substr( $5, 3 )+1)/39.99; \
printf "%s %2.2f %2.2f %3.0f\n", $1, outdoor, indoor, light; \
} ' 20180225_161852_v628_readings.txt


Skrypt wykonuje mega uproszczenie, zakładając że outdoor jest zawsze na minusie, a indoor na plusie, poziom oświetlenia teoretycznie powinien był wyjść w procentach, no ale już sama nie wiem, wygląda w miarę:

Obrazek

Wykresik jak powyżej wykorzystuje funkcjonalność multiplot, możemy na jednym obrazku umieścić kilka wykresów, super wygodne.
W tym przypadku ma to sens o tyle, że zakresy obu temperatur spor się różnią, oświetlenie operuje na zupełnie rozłącznych jednostkach, ale wszystkie trzy strumienie wartości są we wspólnej dziedzinie, którą jest bieżący czas.

multi.gnu pisze:

Kod: Zaznacz cały

set grid
set timefmt '%Y-%m-%d %H:%M:%S'
set xdata time
set xtics 1800
set multiplot layout 3,1
set yrange [-10:0]
set ytics 1
set ylabel "T zewnetrzna ['C]"
plot "<./multiData.sh" using 1:3 with lines lc rgb "navy" lw 3
set yrange [0:30]
set ytics 5
set ylabel "T wewnetrzna ['C]"
plot "<./multiData.sh" using 1:4 with lines lc rgb "red" lw 3
set yrange [0:110]
set ytics 25
set ylabel "oswietlenie [%]"
plot "<./multiData.sh" using 1:5 with lines lc rgb "grey" lw 3
pause 2


Póki co najsłabsze w powyższym skrypciku jest to, że każdy plot wykonuje osobno skrypt pobierający dane, jeżeli cykliczne wywołania zmieniałyby obraz danych - wykresy byłyby przekłamane. Tak więc ten temat muszę jakoś zgłębić, ponieważ multiploty są bardzo użytczną sprawą i warto to poznać lepiej.

Obrazek

W sumie najciekawiej wygląda teraz wykres oświetlenia, widać jak pomału zmierzchało, w międzyczasie jakieś błyski latarką.
Potem zapaliłam lampkę na chwile, potem drugi raz - już na dłużej, do dłubania, no a potem siedzenie w półmroku i przy muzyce kontemplowanie neonowej wystawki.

Obrazek

Mój inny świat.

https://youtu.be/Mo3HYUZfCDk
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)


Wróć do „Retro”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 10 gości