Forum: Mikrocontroller und Digitale Elektronik Eine Arduino Lib für Regeltechnik ?


von Das R. (Firma: Verliererland) (verlierer)


Angehängte Dateien:

Lesenswert?

Realisiere gerade ESP32 Gewächshaus-Controller, der jetzt 10 Werte zu 
meinem Portal www.robosolar.de loggt und möchte die Regel-Logik nicht 
fest codieren. Serverseitige Kontrolle geht auch nicht, da ich nur alle 
30 Minuten drei 10-Minuten Logs hochlade.
Klar könnte ich jetzt in so 2 Tage eigene "Scriptsprache" entwickeln die 
z.B. Lüfter anschaltet wenn (T_in > 35°C) und (V_batt>3.5V)
Hab dann aber eher keine Freude auch noch das webinterface zu 
programmieren. Und über ein beta-Stadium würde ich wohl nie hinaus 
kommen.

Also vielleicht kennt jemand schon so etwas.

Die 10 Werte liegen im Esp32 praktisch schon als float-array for, so 
dass ich diese variablen leicht adressieren kann.
Ich würde das Endresultat (Lüfter an oder aus) dann zeilenweise 
berechnen:

0: T_in > 35.0       => result0 = 1 oder 0
1: V_batt > 3.5      => result1 = 1 oder 0
2. result0 + result1 => result2 = 1 oder 2 oder 3
3. result2 == 3      => Lüfter an oder aus

Es gäbe also das 10-Werte Array, ein Parameter-Array und ein 
Result-Array.
Dazu die Zeilenweise x?y Berechnung.
Wobei "?" ein Operator sein kann wie Wert>Parameter oder Wert>Wert oder 
Wert>Result oder Result>Result.
Jeden Operator + - * / > < == gäbe es also vier mal.
Kodier in einem ascii Zeichen hätte ich Platz für (128-32)/4 = 24 
mathematische/logische Operatoren.

Solch ein "Programm" lässt sich leicht codieren und vom Server zum 
ESP-Client schicken.

Mag aber nicht schon wieder das Rad neu erfinden.

Also Ideen immer zu mir.
das Roland

: Bearbeitet durch User
von Sven B. (scummos)


Lesenswert?

Wenn ich den Anspruch hätte, dass das so allgemein geht, würde ich das 
einfach selber schreiben. So schwer ist das nicht, ist vermutlich in 2-3 
Stunden gemacht, und die Zeit würdest du zum Verstehen, Einbinden und 
Anpassen irgendeiner komischen Bibliothek auch brauchen.

Das Interface würde ich sparen und die Regeln stattdessen in JSON oder 
irgendeiner einfachen DSL (aka, selbst gebauten Mini-Sprache) kodieren.

Das Problem ist einfach zu klein für eine eigene Bibliothek, und zu 
speziell um Teil einer größeren zu sein.

Das mit dem neu erfinden des Rades ist beim Programmieren auch oft 
überbewertet. Das gilt für die allgemeinen, bekannt komplexen Probleme, 
für die es etablierte, zuverlässige, getestete und dokumentierte 
Bibliotheken gibt. Für jedes Obskurum von Github eine seit Jahren nicht 
gewartete 100-Zeilen-Murksbibliothek zu importieren die so ungefähr das 
tut was man braucht, davon ist eher abzuraten. Dann lieber selber 
machen, dann weiß man was man hat.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

NodeMCU?

von Wolfgang (Gast)


Lesenswert?

Das R. schrieb:
> Also vielleicht kennt jemand schon so etwas.

Im Bereich Home Automation gibt es diese ganze Scripterei auch mit 
Datenbank und Visualisierung, z.B. OpenHAB mit InfluxDB/Grafana oder wie 
sie alle heißen. Das läuft dann allerdings eher auf einem Raspberry Pi.

von Patrick (Gast)


Lesenswert?

Wenn es textuell sein soll und es sich lediglich um Logik-Funktionen 
handeln soll, könntest du dich vielleicht an AWL aus der SPS-Technik 
orientieren. Einfaches Und / oder und Grenzwertvergleiche sind damit 
recht einfach zu handhaben und die übersetzund auf dem 
Automatisierungssystem unter Einschränkung der Funktionalitäten auch 
kein Hexenwerk.
Für dein Lüfterbeispiel sähe das dann so aus:
1
U(
2
L T_in
3
L 35.0
4
>R
5
)
6
U(
7
L VBat
8
L 3.5
9
>R
10
)
11
= Luefter

von Das R. (Firma: Verliererland) (verlierer)


Lesenswert?

Stefanus F. schrieb:
> NodeMCU?

Ja an Lua hab ich auch gedacht. Hab aber wohl zu viele I2C Module am 
Esp32..

Sven B. schrieb:
> einfach selber schreiben. So schwer ist das nicht, ist vermutlich in 2-3
> Stunden gemacht, und die Zeit würdest du zum Verstehen, Einbinden und

Ja wer das in 2-3 Stunden schafft ist wirklich gut. Hier meine 3 
Stunden:

**online testen** ---> http://www.robosolar.de/calcy.htm

Die Berechnung wie "(v2>46.3)+(v10>3.0)=2=:s1" erfolgt von links nach 
rechts.
v? = (sensor data)
g? = (global variables)
s? = (system variable like time or outupt-pins)
Der "=" Operator ist der Vergleichsoperator
Der "=:" Ist der Zuweise-Operator

Man kann also Werte für spätere Berechnung in g? speichern.
Mit s? kann man so auch die aktuelle Uhrzeit in die Berechnung 
einbeziehen und zum Beispiel einen Lüfter für 2 Minuten anschalten..

Und nun freue ich mich auf bugs :-)
1
<html>
2
<body>
3
<div id=demo></div>
4
<script>
5
6
var s;  // the calculation string 
7
var aValue;   // the array of values
8
var aGlobal;    // the array of global variables
9
var aSystem;    // the array of system variables, 
10
//        some readonly like time, some writeonly like output bits
11
12
function GetTypeArray(sType)
13
{
14
  switch(sType)
15
  {
16
  case "v":  return aValue;
17
  case "g":  return aGlobal;
18
  case "s":  return aSystem;
19
  }
20
  return 0;  
21
}
22
  
23
function Calc(s)
24
{
25
  var iLen = s.length;
26
  var o1 = NextNum(s,0,iLen);
27
  while(1)
28
  {
29
    var sOp = s.charAt(o1.j);
30
    var o2 = NextNum(s,o1.j+1,iLen);
31
    var f = 0;
32
    switch(sOp)
33
    {
34
    case ">":  f = (o1.fRet > o2.fRet) ? 1 : 0;  break;
35
    case "<":  f = (o1.fRet < o2.fRet) ? 1 : 0;  break;
36
    case "=":  f = (o1.fRet == o2.fRet) ? 1 : 0;  break;
37
    case "+":  f = o1.fRet + o2.fRet;  break;
38
    case "-":  f = o1.fRet + o2.fRet;  break;
39
    case "~":  
40
      if (!o2.t)  // syntax error: can not set o1.f to a constant variable
41
        return 0;
42
      var a = GetTypeArray(o2.t);
43
      a[o2.fRet] = f = o1.fRet;
44
      break;
45
    default:  // unkown operator
46
      return 0;
47
    }
48
    if (o2.j >= iLen)
49
      break;
50
    o1 = {"t":0,"i":o2.i,"j":o2.j,"fRet":f};
51
  }
52
  return f;
53
}
54
55
function NextNum(s,i,j)
56
{
57
  //return 0;
58
  while(i<j)
59
  {
60
    var c = s.charAt(i++);
61
    if (c == "(")
62
    {
63
      var iOpen = 1;
64
      var j2=i;
65
      while(j2<j)
66
      {
67
        var c = s.charAt(j2++);
68
        if (c == "(")
69
        {
70
          iOpen++;
71
        }  
72
        if (c == ")")
73
        {
74
          iOpen--;
75
          break;
76
        }  
77
      }
78
      if (iOpen>0)  
79
        return 0;
80
      //return NextNum(i,j2);
81
      return {"t":0,"i":i,"j":j2,"fRet":Calc(s.substr(i,j2-i-1))};
82
    }
83
    var cType = 0;  // expecting this to be a constant number
84
    var j2=--i;
85
    while(j2<j)
86
    {
87
      switch(c)
88
      {
89
      case "+":
90
      case "-":
91
      case ".":
92
        if (cType)  // syntax error
93
          return 0;
94
      case "0":
95
      case "1":
96
      case "2":
97
      case "3":
98
      case "4":
99
      case "5":
100
      case "6":
101
      case "7":
102
      case "8":
103
      case "9":
104
        break;
105
      default: 
106
        if (cType)
107
        {
108
          var iPos = s.substr(i,j2-i);
109
          var a = GetTypeArray(cType);
110
          var f=a[iPos];
111
          return {"t":cType,"i":i,"j":j2,"fRet":f};
112
        }
113
        if (j2>i)  // we already parsed a number
114
        {
115
          return {"t":0,"i":i,"j":j2,"fRet":s.substr(i,j2-i)};
116
        }
117
        cType = c;  // seems to be something linke "v1"
118
        i++;
119
      }
120
      var c = s.charAt(++j2);
121
    }
122
    return {"t":cType,"i":i,"j":j2,"fRet":s.substr(i,j2-i)};
123
  }
124
}  
125
126
aValue = [0,16.7,64.4,95.5,18.3,43.7,95.5,99,6.5,43.6,4];
127
aGlobal = [0,0,0,0,0,0,0,0,0];
128
aSystem = [1556474970,0];
129
130
function Demo(sFormula)
131
{
132
  sCalc = sFormula.replace("=:","~");
133
  var sRes = Calc(sCalc);
134
  var s = "v? = "+aValue.join(" , ") + " (sensor data)<br>"
135
    +"g? = "+aGlobal.join(" , ") + " (global variables)<br>"
136
    +"s? = "+aSystem.join(" , ") + " (system variable like time or outupt-pins)<br>"
137
    +"calculate " + sFormula + "<br>"
138
    +"result: " + sRes + "<br>"
139
    +"next: <form onSubmit='return Demo(this.s.value,this)'><input name=s value='"+sFormula+"' size=50><input type=submit value='calculate'></form><br>";
140
  var r = document.getElementById("demo");
141
  if (r)
142
    r.innerHTML = s;
143
  return false;
144
}
145
146
Demo("(v2>46.3)+(v10>3.0)=2=:s1");
147
148
</script>
149
</body>
150
</html>

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Das R. schrieb:
> tefanus F. schrieb:
>> NodeMCU?

meine empfehlung wäre MicroPython!!!

ich finde mit python kann man sehr effektiv/schnell solche aufgaben 
erledigen und beispiele/projekte/lib's gibt es reichlich zum 
starten/lernen/anwenden.

ich programmiere immer mehr in mpy und bin begeistert wie "einfach" sich 
viele aufgaben in mpy erledigen lassen. in c muss ich da deutlich mehr 
"klimmzüge" machen und python kenntnisse kann man auch sonst gut 
ausserhalb embedded anwendungen gebrauchen.


mt

von Das R. (Firma: Verliererland) (verlierer)


Lesenswert?

So das portieren auf Arduino Code hat schon fast doppelt so lange 
gedauert:
1
#define _DEMO_ 1
2
#include "calcy.h"
3
4
// this is the data like you will use in your project
5
float aG[9] = {0,0,0,0,0,0,0,0,0};
6
float aS[2] = {1556474970,0};
7
SyncData oData = {1556474000,0,16.7,64.4,95.5,18.3,43.7,95.5,99,6.5,43.6,4};
8
9
10
void setup() {
11
  Serial.begin(115200);
12
13
  // now point the calcy data arrays to your true data
14
  aValue = (float*) &oData; aValue++;
15
  aGlobal = (float*) &aG;
16
  aSystem = (float*) &aS;
17
18
  String sCalc = "(v2>46.3)+(v10>3.0)=2~s1";
19
  String sError;
20
  float fResult = Calc(sCalc,sError);
21
22
  if (sError)
23
    Serial.println(sError);
24
}
25
26
void loop() {}

und die calcy.h
1
#define _DEBUG_ 1
2
3
#ifdef _DEBUG_
4
  #define DEBUG(txt, val) Serial.print(txt); Serial.print(": "); Serial.print(val); Serial.print("\t"); 
5
  #define DEBUGLN(txt, val) Serial.print(txt); Serial.print(": "); Serial.println(val)
6
#endif
7
#ifndef _DEBUG_
8
  #define DEBUG(txt, val)
9
  #define DEBUGLN(txt, val)
10
#endif
11
12
13
float* aValue;   // the array of values
14
float* aGlobal;    // the array of global variables
15
float* aSystem;    // the array of system variables, 
16
17
void SetArrayValue(char sType,int i, float f)
18
{
19
  switch(sType)
20
  {
21
  case 'v': aValue[i] = f;  break;
22
  case 'g': aGlobal[i] = f;  break;
23
  case 's': aSystem[i] = f;  break;
24
  }
25
  DEBUGLN("\tSetArrayValue",String(sType)+","+String(i) + "," + String(f));
26
}
27
28
float GetArrayValue(char sType,int i)
29
{
30
  switch(sType)
31
  {
32
  case 'v': 
33
    DEBUGLN("\tGetArrayValue(v)",String(i)+") = "+String(aValue[i]));
34
    return aValue[i];
35
  case 'g': return aGlobal[i];
36
  case 's': return aSystem[i];
37
  }
38
  return 0;
39
}
40
41
typedef struct __attribute((__packed__))
42
{
43
  char t;
44
  int i;
45
  int  j;
46
  float  fRet;
47
} Result;
48
49
float Calc(String s, String& sError);   // recursive programming -> declaration neccessary
50
Result NextNum(String s,int i, int j, String& sError)
51
{
52
  while(i<j)
53
  {
54
    char c = s.charAt(i++);
55
    if (c == '(')
56
    {
57
      int iOpen = 1;
58
      int j2=i;
59
      while(j2<j)
60
      {
61
        char c = s.charAt(j2++);
62
        if (c == '(')
63
        {
64
          iOpen++;
65
        } 
66
        if (c == ')')
67
        {
68
          iOpen--;
69
          break;
70
        } 
71
      }
72
      if (iOpen>0)
73
      {
74
        sError += s + " : syntax error too many '('\n";
75
        return {0,i,j2,0};
76
      }
77
      return {0,i,j2,Calc(s.substring(i,j2-1),sError)};
78
    }
79
    char cType = 0;  // expecting this to be a constant number
80
    int j2=--i;
81
    while(j2<j)
82
    {
83
      switch(c)
84
      {
85
      case '+': case '-': case '.':
86
        if (cType)  // syntax error
87
        {
88
          sError += s + " : syntax error #2\n";
89
          return {0,i,j2,0};
90
        }
91
      case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
92
        break;
93
      default: 
94
        if (cType)
95
        {
96
          int iPos = s.substring(i,j2).toInt();
97
          return {cType,i,j2,GetArrayValue(cType,iPos)};
98
        }
99
        if (j2>i) // we already parsed a number
100
        {
101
          return {0,i,j2,s.substring(i,j2).toFloat()};
102
        }
103
        cType = c;  // seems to be something linke "v1"
104
        i++;
105
      }
106
      j2++;
107
      c = s.charAt(j2);
108
    }
109
    return {cType,i,j2,s.substring(i,j2).toFloat()};
110
  }
111
}
112
113
float Calc(String s, String& sError)
114
{
115
  DEBUGLN("Calc()",s);
116
  int iLen = s.length();
117
  Result o1 = NextNum(s,0,iLen,sError);
118
  float f = 0;
119
  while(1)
120
  {
121
    char sOp = s.charAt(o1.j);
122
    Result o2 = NextNum(s,o1.j+1,iLen,sError);
123
124
    switch(sOp)
125
    {
126
    case '>': f = (o1.fRet > o2.fRet) ? 1 : 0;  break;
127
    case '<': f = (o1.fRet < o2.fRet) ? 1 : 0;  break;
128
    case '=': f = (o1.fRet == o2.fRet) ? 1 : 0; break;
129
    case '+': f = o1.fRet + o2.fRet;  break;
130
    case '-': f = o1.fRet + o2.fRet;  break;
131
    case '~': 
132
    {
133
      if (!o2.t)  // syntax error: can not set o1.f to a constant variable
134
        return 0;
135
      f = o1.fRet;
136
      SetArrayValue(o2.t,(int)o2.fRet,f);
137
      break;
138
    }
139
    default:  // unkown operator
140
      return 0;
141
    }
142
    if (o2.j >= iLen)
143
      break;
144
    //o1 = {"t":0,"i":o2.i,"j":o2.j,"fRet":f};
145
    o1.t=0; o1.i=o2.i; o1.j=o2.j; o1.fRet=f; 
146
  }
147
  DEBUG("Calc()", s + "\treturning:" + String(f));
148
  return f;
149
}
150
151
#ifdef _DEMO_
152
typedef struct __attribute((__packed__))
153
{
154
  uint32_t  iTime;
155
  uint32_t  wData;  // bits 0..7 = iAlarms
156
  float fInT; // temperature
157
  float fInH; // humidity
158
  float fInP; // preassure
159
  float fOutT;
160
  float fOutH;
161
  float fOutP;
162
  float fSoilH; // moisture
163
  float fSoilA; // acid
164
  float fSoilL; // light
165
  float fBatt;  // battery voltage
166
} SyncData;
167
#endif

das Roland
der kleine Physiker :-)

von Das R. (Firma: Verliererland) (verlierer)


Lesenswert?

so hab den ganze code zu github hochgeladen :-)

https://github.com/RoboDurden/MicroControlLib

von Pandur S. (jetztnicht)


Lesenswert?

> float

.. alles klar. Aber meist nicht noetig.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.