TaskScheduler: Welche Library sinnvoll? | Dyn. parametriserte Tasks erzeugen?

Hallo liebe Community,

mit dem Arduino (derzeit eher ESP8266) noch in den Kinderschuhen, baue ich mir gerade eine universelles und strukturiertes Template für eine Reihe verschiedener Aufgaben (Aktoren, Sensoren, Kombi) im Haus. Allen gemein ist: MQTT und WLAN. Der Teil läuft auch schon sehr verlässlich. Auch Adafruit/Neopixel, etc geht (statisch) bereits wunderbar oder Sensorik (BME860, etc.). Dabei ist mir der Bedarf einer Aternative zu delay() völlig klar, ein TaskHandler ist sicher sinnvoll., Nur bin ich unsicher, was die richtiige Lösung ist...

Frage 1: Welche Bibliothek? Welche ist derzet die "beste Wahl"? Bin zunächst auf Scheduler.h gestoßen, aber die ist schon eine weile ohne Fortschritt. Die meisten Treffer finde ich zu TaskScheduler.h. Die Library ist auch aktiv in der Entwicklung. Tasks, um kein Delay zu haben, Ernegie-sparsamer zu sein (IDLE) und ohne delay-Verzögerung reaktiv zu sein,... Diesen Teil konnte ich grundsäctzlich bereits mit TaskScheduler.h erfüllen..

--> Ist diese Bibliothek auch eine Empfehlung in dieser Runde?

Frage 2:* Gerade in der LED-Aktorik möchte ich dynamisch parametrsierte Tasks erreichen. Ich weiß vorher noch nciht, wie viele Tasks undmit welchen Werten.
Einfaches Beispiel zur Veranschaulichung:

  • Per MQTT ("1,1000,255,0,0,0") Pixel 1 mit sekündlich in rot blinken lassen und
  • mit enem anderen Wert ("2,500,0,0,255") zum selben Topic parallel Pixel 2 doppelt so schnell in blau blinken lassen.
    Ich würde denken, dass man nur eine Neopixel-Blink-Methode/Funktion braucht, die 2 Tasks zu zwei dynmaisch erzeugten Objekten/Instanzen werden (addTask? New task?). und mit einem MQTT-Wert (1,0,0,0,0,0) kann ich das Pixel 1 wieder ausschalten (deleteTask?).

Mir ist das OO-Prinzip an sich klar, aber ich bin ich ziemllich ungeübt damit und mit CPP habe ich erst vor wenigen Tagen mit Arduino angefangen. Auch nach Stunden kam ich mit den Beispielen zur Library nicht zum Erfolg (example8_LTS, example21_OO_Callbacks,...).

--> Wie löst man das mit TaskScheduler.h (oder einer empfehlenswerteren Library): Per MQTT kommt eine Wert herein: Was ist Global, setup(), loop() zu machen (außer "Scheduler runner;" und "runner.execute();")? Wie ist der Task mit den Paramtern zu instanziieren? Wie sähe eine einfache universelle Blink-Methode aus? Oder ist dies so gar nicht sinnvoll zu lösen?

Danke für das Stubsen in die richtige Richtung! :slight_smile:

im Extremfall willst du aber jeden Pixel deines Strips blinken lassen - oder Annahme "nur maximal 20" (oder eine andere Zahl)?
wenn "unbeschränkt" - Wie viele Pixel hast du?

Wenn "unbeschränkt" - genug Speicher für so etwas hast du frei?
Pixel Anzahl mal Speicherbedarf je Blink Objekt

Das beste TaskSystem ist natürlich mein TaskSystem.
Direkt nach FreeRTOS.

Und ja, es kann Tasks dynamisch anlegen.

Eine einfache Blinktask würde darin so aussehen:

#pragma once

#include <CooperativeTask.h>


class BlinkTask: public Task
{
  protected:
    const byte pin;
    const unsigned long interval;
  
  public:
    BlinkTask(const byte pin,const unsigned long interval):
       pin(pin),
       interval(interval)
    {
    }
    
    virtual void init() 
    {
      Serial.print("BlinkTask begin, pin: "); Serial.println(pin);
      pinMode(pin,OUTPUT);
    }
    
    virtual void run() 
    {
      TaskBlock
      {
        digitalWrite(pin,HIGH);
        taskPause(interval);
        digitalWrite(pin,LOW);
        taskPause(interval);
      }
    }
    

    virtual ~BlinkTask()
    {
      digitalWrite(pin,LOW);
      pinMode(pin,INPUT);
    }

};

CooperativeTask.zip (10 KB)

1 Like

Danke schon mal Euch zwei! :slight_smile:

@noiasca: Die Begrenztheit meiner HW (derzeit ein paar Wemos D1 mini) ist klar... :slight_smile: Ich gehe von wenigen (sagen wir 5) aus. Hintergrund ist auch eher nicht die Anzahl, sondern ich weiß nicht wann und mit welchen Parametern (hier Pixel + RGB) der Task erforderlich wird; das Task-Objekt muss "irgendwie" (daran bin ich gescheitert) dynamisch angelegt und mit Parametern versorgt werden - die im besten Fall sogar während des Laufs sogar geändert werden können, ohne es zu löschen und neu anzulegen - also z.B. den RGB-Wert ändern.

Wenn ich es prinzipiell mit meinem Template geschafft habe und mir meine HW für eine Anforderung später mal Grenzen aufzeigt, dann ist das mit anderer HW für ein paar Euro lösbar... Sketch da drauf und weiter geht's... :slight_smile:

@combie: So, so... :wink: Vielleicht bin ich auch nur furchtbar old-school, aber wenn ich mich für eine Library entscheide, verstehe ich einerseits warum (besonderes wenn es nachvollziehbare Gründe/Kriterien gibt, warum A für diesen Zweck besser ist als B oder C) und baue gerne auf Libraries, bei denen ich das Gefühl habe, dass sie auch morgen noch gepflegt werden. Da ich noch ganz neu "im Arduino-Geschäft" bin und es schlicht noch nicht einschätzen kann: Welche Aussagekraft hat es, wenn eine Bibliothek nicht in der Arduino-IDE angeboten wird? Oder habe ich Deine dort nur schlicht falsch gesucht?

Aber das bitte nicht falsch verstehen - ich Danke Dir sehr, für Deinen Vorschlag und werde ihn gerne mal testen - und vielleicht ist er ja auch perfek. Dazu auch direkt eine konkrete Frage: Weil ich auch Anwendungen mit Batterieversorgung plane: Funktioniert der Stromspar-Mechanismus damit auch im IDLE - dazu hatte ich bei einzelnen Bibliotheken doch erhebliche Spar-Potentiale gelesen zu Gunsten langer Batterie-Laufzeiten.
Und: Wie wäre der Aufruf des Tasks z.B. bei Eintreffen eines MQTT-Werts und wie wird der Task gelöscht? Wie gesagt...bin ganz neu im CPP...

Vielleicht ist mein Wunsch, nur eine Task/Schdule-Libriry nutzen zu wollen für mehrere Zwecke auch mein Fehler...

Und: Grundsätzlich habe ich bslang keinerlei Bedraf an RTOS, keine meiner bisher geplanten Anwendungen ist in irgend einer Weise Zeitkritisch oder exakt.

also bei "5" würde ich mir keine weiteren grauen haare wachsen lassen.

Da mach ich mir eine Klasse der ich den Pixel/Intervall/Farbe übergebe und lass das Ding blinken.
Die Objekte in ein Array über 5 und fertig.

Dynamisch ist das nicht. Klassische setter Methoden halt.

Wodurch wird einer dieser 5 Blinker wieder frei für die Verwendung eines anderen Pixels?

@ard_work
Deine Anforderungen erfüllt meine Lib, soweit ich das bisher erkennen kann.

Es ist OK, wenn du mein "Produkt" abwerten möchtest.
Nur, ist das einer positiven Kommunikation wenig zuträglich.

Hallo,
ich verstehe jetzt noch nicht warum das dynamisch sein soll. Wenn Du 10 LED´s hast und die einzeln unabhängig voneinander irgendwie blinken lassen willst dann benötigst Du dazu genau 10 Blinker. 11 mach keinen Sinn sind ja nur 10 Hardware Teile vorhanden. Alles einzen und unabhängig voneinander zu sehen geht auch nicht, weil spätestens mit LED.show() sprichst Du den gesamten Streifen an. Dazu brauchst Du einen 11. Timer Schau Dir die Fastled leb an , die hat auch Methoden zum zeitlichen Ablauf. Letztlich kannst Du damit auch was anderes machen.

Aber letztlich hat Deine Frage ja nichts mit den LED zu tun,es geht ja ehr um eine grundsätziche Frage. Task, Timer Lib´s gibts sicher viele, wichtig ist das Du die Funktion verstehst. Nimm die die dir am besten passt, da musst Du etwas rumprobieren. Jede hat das sicher Vor und Nachteile. Wenn Du Dir millis() richtig anschaust und ein bischen tiefer einsteige willst kannst Du dir ja auch selber eine Classe schreiben die Dir ein paar Methoden zur Verfügung stellt die genau auf Deinen Fall passen.

Heinz

ard_work:
Danke für das Stubsen in die richtige Richtung! :slight_smile:

Ich haue Dir jetzt mal meine Meinung um die Ohren, das willst Du nicht lesen, das könnte zu blauen Flecken führen ;D

Da ich nur mit dem ESP32 arbeite, gelten meine Aussagen für diesen.

ard_work:
... mit dem Arduino (derzeit eher ESP8266) ...

Ein ESP8266 ist kein Arduino und Du möchtest ihn auch nicht wie einen Arduino programmieren. Die Arduino-IDE scheint mir daher das falsche Werkzeug, nimm die von Espressif verwendete IDE!

ard_work:
Dabei ist mir der Bedarf einer Aternative zu delay() völlig klar, ein TaskHandler ist sicher sinnvoll., Nur bin ich unsicher, was die richtiige Lösung ist...

Die Lösung heißt millis()!

Natürlich kannst Du mit Kanonen auf Spatzen schießen, aber eine TaskHandler-Arduino-Bibliothek verdeckt nur Deine Fähigkeit, selbst ein ordentliches Programm zu schreiben. Zumindest suggeriert mir das Dein Text, sonst kenne ich Dich ja nicht. Solltest Du doch so gut sein, wie ich beispielsweise combie einschätze, dann hast Du Dich schlecht dargestellt.

ard_work:
... baue gerne auf Libraries, bei denen ich das Gefühl habe, dass sie auch morgen noch gepflegt werden. ...
...
Und: Grundsätzlich habe ich bslang keinerlei Bedraf an RTOS, keine meiner bisher geplanten Anwendungen ist in irgend einer Weise Zeitkritisch oder exakt.

Das ist doch ein Widerspruch. Warum willst Du irgendeine Arduino-Bibliotherk nutzen - zur Erinnerung, der ESP8266 ist kein Arduino - wenn Du vom Hardwarehersteller die von Dir nachgefragten Bibliotheken oder APIs mitgeliefert bekommst? Sowas wie

previous_cap_value = (uint32_t *)malloc(CAP_SIG_NUM * sizeof(uint32_t));
xTaskCreate(disp_captured_signal, "mcpwm_config", 4096, NULL, 5, NULL);

müßte doch genau passen. Wenn Deine LEDs dadurch etwas genauer blinken, dürfte das doch kein Problem darstellen ::slight_smile:

Kräftiger aber gut gemeinter Schubs von mir!

so gut sein, wie ich beispielsweise combie einschätze,

Ich danke dir für die Blumen!
Kann allerdings deine Beurteilung nicht unterstützen, weil ich mich selber nicht beurteilen mag.

Weiß aber, dass die CooperativeTask, die Ausgeburt langjähriger C und C++ Arbeit ist.
Überlegt hatte ich schon, die über den Librarymanager zu publizieren.
Bräuchte dazu aber einen, oder eine, Dokumentationskraft.
Die Wahl der schönen Worte, ist sicherlich nicht meine Kernkompetenz.

Wenn der ard_work nicht dem Link in dem Posting folgen mag, ist das seine Sache. Auch wenn fehlendes Github negativ ausgelegt wird.
Gegen das alles kann ich nichts ausrichten, denn der Kampf gegen die Windmühen, da bin ich zu faul für.

Anforderung 1:
Dynamisches erzeugen von Tasks!
Wird voll erfüllt.
Siehe folgendes Beispiel.
Dort erzeugt eine MasterTask alle 10 Sekunden ein Blink Kind, und zerstört es nach 10 Sekunden wieder.

Anforderung 2:
Übergeben von Parametern an die Task!

Um Parameter an die Task zu übergeben bieten sich die üblichen "Dependency Injection" Wege an.
Konkret:
Konstant Injection, Übergabe zur Kompilezeit (entweder über TemplateParameter oder/und Literale)
Konstruktor Injection, Übergabe zur Erzeugungszeit
Member/Setter Injection, Übergabe zur Laufzeit

Keiner dieser Wege wird von meiner Lib bevorzugt, oder gar ausgeschlossen.
Nicht implementiert. Noch nicht mal im Ansatz nicht.
Woher sollte ich, als der LibErsteller, auch wissen, welche Parameter wann gewünscht sind.

Das ist auch das, das einzige, was mir an FreeRTOS nicht so gefällt.
Da kann man einen Parametersatz beim Etablieren der Task übergeben.
Der Weg ist nicht Typesicher.
Das Manko gibt es bei mir nicht. Hier kann man das Typesicher gestalten.

#include <CooperativeTask.h>

class BlinkTask: public Task
{
  protected:
    const byte pin;
    const unsigned long interval;
  
  public:
    BlinkTask(const byte pin,const unsigned long interval):
       pin(pin),
       interval(interval){}
    
    virtual void init() override
    {
      pinMode(pin,OUTPUT);
    }
    
    virtual void run() override
    {
      TaskBlock
      {
        digitalWrite(pin,HIGH);
        taskPause(interval);
        digitalWrite(pin,LOW);
        taskPause(interval);
      }
    }
};

class MasterTask: public Task
{
  protected:
    unsigned long interval;
    BlinkTask* blinker;
  
  public:
    MasterTask(const unsigned long interval):interval(interval),blinker(nullptr){}
    
    virtual void run() override
    {
      TaskBlock
      {
        blinker = new BlinkTask(13,500);
        (*blinker).init();
        taskPause(interval);
        delete blinker;
        blinker = nullptr;
        taskPause(interval);
      }
    }
    virtual ~MasterTask() override
    {
      delete blinker;
    }
};

MasterTask master(10000);
   
void setup() 
{
  Scheduler::instance().init();
}

void loop() 
{
  Scheduler::instance().run();
}

noiasca:
Da mach ich mir eine Klasse der ich den Pixel/Intervall/Farbe übergebe und lass das Ding blinken.
Die Objekte in ein Array über 5 und fertig.

also ich hab mich da mal dran gesetzt. Ich schreibe ausdrücklich das hat nichts mit "Tasks" zu tun. Es ist ein primitives "BlinkWithoutDelay". Es erfüllt aber aus meiner Sicht die Anforderung.

Zunächst mal was ich mir Anfangs überlegt habe auf Papier gebracht - wer's lesen kann ... hier bitte:
20210105_202217m.jpg

Von der Blink Klasse gibt es aktuell 5 "Programmplätze". Ein Objekt kann im Prinzip jeden Pixel aufnehmen. Man muss halt im loop laufend die Objekte anticken.

Umfangreich schaut eigentlich nur das Mensch-Maschine Interface aus, ich habe mich kurzfristig für die Serielle entschieden. Man gibt 0 .. 9 ein und die jeweilige LED wird blinkend ein oder ausgeschaltet. Gibts keinen freien "Programmspeicherplatz" mehr, kommt es zu einer Warnung und man muss vorher eine andere LED ausschalten. Zwei Zeilen sind ziemlich ähnlich/Duplikate, aber ist ja nur ein Demo.

/* einzelne Neopixel blinken lassen
   "dynamisch" steuerbar über Serielle Schnittstelle
   
   https://forum.arduino.cc/index.php?topic=721403
   by noiasca
*/

#include <Adafruit_NeoPixel.h>

const uint16_t LED_COUNT = 10;
const uint8_t LED_PIN = 12;   // Pin richtig stellen!

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

enum class State {FREE, ISON, ISOFF};

class Blink
{
  protected:
    byte onRed = 128, onGreen = 128, onBlue = 128, offRed = 0, offGreen = 0, offBlue = 0;
    uint32_t previousMillis;
    uint16_t onInterval, offInterval;
    State state = State::FREE;
    byte pixel;

  public:
    Blink()
    {}

    void start(byte _pixel, uint16_t _onInterval, byte _onRed, byte _onGreen, byte _onBlue)
    {
      pixel = _pixel;
      onInterval = _onInterval;
      onRed = _onRed;
      onGreen = _onGreen;
      onBlue = _onBlue;
      offInterval = _onInterval;
      state = State::ISOFF;
    }

    byte getPixel()
    {
      return pixel;
    }

    State getState()
    {
      return state;
    }

    void end()
    {
      strip.setPixelColor(pixel, 0);
      strip.show();
      state = State::FREE;
    }

    void tick()
    {
      if (state == State::ISON && millis() - previousMillis > onInterval)
      {
        strip.setPixelColor(pixel, strip.Color(offRed, offGreen, offBlue));
        strip.show();
        previousMillis = millis();
        state = State::ISOFF;
      }
      else if (state == State::ISOFF && millis() - previousMillis > offInterval)
      {
        strip.setPixelColor(pixel, strip.Color(onRed, onGreen, onBlue));
        strip.show();
        previousMillis = millis();
        state = State::ISON;
      }
    }
};

Blink blink[5];
const size_t noOfBlink = sizeof(blink) / sizeof(blink[0]);

void setup() {
  Serial.begin(115200);
  strip.begin();
  strip.clear();
  strip.show();

  // start 3 of 5 blink programs:
  blink[0].start(0, 1000, 0x88, 0x88, 0x88);
  blink[1].start(2, 500, 0x88, 0x00, 0x00);
  blink[2].start(4, 700, 0x00, 0x88, 0x00);
}

void loop() {
  for (auto &i : blink) i.tick();
  readSerial();
}

void readSerial() {
  if (Serial.available()) {
    char received = Serial.read();
    if (received >= 0x30 && received <= 0x39)
    {
      byte newPixel = received - 0x30;
      Serial.print(F("entered ")); Serial.println(newPixel);
      bool found = false;
      // Step 1: check if we have to stop a running program or if we find an old programm for this pixel
      for (size_t i = 0; i < noOfBlink; i++)
      {
        if (blink[i].getPixel() == newPixel)       // actual Program is for this pixel
        {
          if (blink[i].getState() != State::FREE)  // is running
          {
            blink[i].end();
            Serial.print(F("ended in program ")); Serial.println(i);
            found = true;
            break;
          }
          else                                    // not running/free - reuse blink progam
          {
            blink[i].start(newPixel, random(500, 1000), random(256), random(256), random(128));
            Serial.print(F("restarted in program ")); Serial.println(i);
            found = true;
            break;
          }
        }
      }
      // Step 2: find a new (empty) programm for this pixel
      if (found == false)
      {
        for (size_t i = 0; i < noOfBlink; i++)
        {
          if (blink[i].getState() == State::FREE)  // that's a free program
          {
            blink[i].start(newPixel, random(500, 1000), random(256), random(256), random(128));
            Serial.print(F("started in program ")); Serial.println(i);
            found = true;
            break;
          }
        }
      }
      if (found == false)
      {
        Serial.println(F("no free program available. Stop one of the blinking LEDs."));
      }
    }
  }
}

ob ich noch ne Variante mit new / delete mache weis ich noch nicht. Wenn es eh auf 5 begrenzt ist, stehts imho nicht dafür.

20210105_202217m.jpg

Das finde ich gar nicht so schlecht!
Ein fester Pool von "Tasks", auch wenn du sie nicht so nennst.

Das befreit einen auf jeden Fall von der dynamischen Speicherverwaltung, welche auf kleinen AVR durchaus Sorgen bereiten kann.


OK, auf ESP8266 eher nicht, die haben reichlich Speicher.

Und bei den ESP32 sowieso nicht, denn die haben ja schließlich 2 Kerne und FreeRTOS fest im Arduino Core verankert.


Ich schreibe ausdrücklich das hat nichts mit "Tasks" zu tun. Es ist ein primitives "BlinkWithoutDelay".

Nichts anders machen meine CooperativeTask!
Nur eben im Etikett und Design unterscheidet es sich.
Es ist substantiell das gleiche.

@combie: Ich habe mich offenbar unglücklich ausgedrückt... denn das, was Du verstanden hast, war ganz sicher nicht meine Intention und tut mir leid. Mir fehlt schlicht noch das Handwerkzeug, um zu beurteilen, wie gute Deine Lösung ist. Ich bin mit dem Thema und CPP ganz am Anfang - als bei weitem kein Crack wie Du/viele hier.

Es ist nur so, dass ich gerade in die Stadt "Arduino" gezogen bin, nach ein paar netten Versuchen mangels WLAN dann in den Vorort ESP8266 und dort nun auf dem Marktplatz stehe und rings herum sind viele Pizzerien, die alle sagen, sie hätten die beste. Und nun kommst Du auf meine Frage zu den anderen Pizzerien mit einem eigenen Lieferservice um die Ecke... :slight_smile:
Ich hoffe, Du verstehst jetzt besser... ich kann noch gar nicht beurteilen, wie gut Dein Produkt ist (es ist wohl möglich das beste für mich) und versuche nur zu verstehen... Bei Deinem ersten Post fehlte mir noch der Aufruf-Kontext. Danke für Deine 2. Nachricht, damit werde ich es gerne testen. Und eine Ahnung einer Meinung entwickeln. Ich habe keine Erfahrung mit Klassen/CPP.

Bei Pizza ist's viel leichter, wiel da brauche ich nur x Tage und meinen persönlichen Geschmackssinn. Hier ist anders, hier gibt es sicher einen ganzen Sack objektive Kriterien, die ich noch gar nicht kenne (und daher fragte) und dazu noch meine eigene, noch sehr beschränkten Möglichkeiten und Kenntnisse - und den schon viel zu weitreichenden Plänen und dem Wunsch nach "eine universellen WLAN-MQTT-Task-Template", dass ich für alles nehmen und nur anpasse, ob ph-Wert draußen am Pool oder die 3 Strips inkl. VOC-Sensor im Kinderzimmer oder die Pegelmessung Zisterne inkl. CO-Messung oder oder oder...

@Rentner: Ich behaupte, ich brauche nur 1 Blinker, aber x Instanzen mit unterschiedlichen Parametern. Im Kontext von WS2811 werde ich immer mehr LEDs haben, als mein HW Ressourcen...

Und in der Tat ist LED durchaus wichtig, aber es geht um eine grundsätzliche Frage. Mir erschien (mit meiner begrenzten Erfahrung) auch millis wie delay() der falsche Weg, weil in der Zeit anderer Prozesse gestört werden (z.B: ein neuer MQTT-Wert soll nahezu unmittelbar verarbeitet werden) und zudem der IDLE-Verbrauch unnötig höch ist (für Batteriebetreib). ABer da mag ich auch falsch liegen. Eine eigene Klasse werden ich mangels Zeit vermutlich nicht so schnell dazu schreiben - genau deswegen möchte ich mich ja dem Ergebnis erfahrener Experten "hingegeben " und deren Bibliothek benutzen.

@agmue: Ich hab emit Arduino angefanngen, fand die auch klasse, aber für meine aktellen Anwendungen brauche ich WLAN und daher bin ich auf ESP8266 gestoßen und begeistert mich derzeit mehr. Da die Arduino-IDE auch ging, blieb ich da. Ich wusste nicht, dass es eine Alternativ egibt. Offen gesagt habe ich mich mit dem Unterschied Arduino<->ESP8266 noch gar nicht beschäftigt (über WLAN ja/nein hinaus)... war als Laie irgendwie ähnlich mit A/D+ I2C-Pins und gleicher IDE... das hatte auch seinen vereinfachenden Charme...

Also Dein Tipp: Andere IDE verwenden? Okay, muss ich mir anschauen...
Und: Damit bekomme ich für meine Frage Lösungen, die es für den Arduino gar nicht gibt? Spannend, muss ich mir anschauen... Wenneglich ich Dein Code-Beispiel (noch) genau null begreife. Danke für den Schubs! :slight_smile:

@noiasca: lieben Dank auch für Dein Beispiel. Auch hier gilt: Muss ich mir anschauen, testen, verstehen, Meinung bilden...

@all: Ich muss das mal alles testen... Danke! :smiley:

Was mich wundert: Es gab niemanden hier, der zu einer vorhandenen Bibliothek wie z.B. TaskScheduler geraten hat... das fand ich irgendwie unerwartet... ich dachte es wäre gerade sinnvoll, Bibliotheken zu nutzen und nicht alles jedes Mal neu zu "erfinden" - aber in Bezug auf asks liege ich da wohl weit ab der Praxis... ich hoffte auf "runter laden, INCLUDE, richtig anwenden, fertig!" Die Welt ist hier nicht so einfach wie bei WLAN und MQTT - wo es genau so in recht kurzer Zeit klappte und sich rasch ein Template für mich ergab...

Ich bitte dich: Rechtfertige dich nicht ungefragt!
Damit zeigst du eher Halsstarrigkeit, als Einsicht.
Auf die Art stabilisierst du deinen Zustand!
Aber das ist ja nicht das, was du willst, hoffe ich.
Ich möchte, dass du lernst. Du doch auch?

Mit anderen Worten:
Ich, und viele Andere, sehen auch so deinen Stand, ohne dass du dich ohne Grund selbst erniedrigst.

Andererseits:
Wenn dich jemand fragt, warum du etwas tust, dann antworte offen und ehrlich.

Bei Deinem ersten Post fehlte mir noch der Aufruf-Kontext.

Der findet sich in der von mir angehangenen Zip!
Nur nicht speziell auf deine Probleme bezogen.

Tipp 2:
Die Library ist im Quelltext.
Den kannst du analysieren und deinen Bedürfnissen anpassen.

ich kann noch gar nicht beurteilen, wie gut Dein Produkt ist (es ist wohl möglich das beste für mich)

Das kann ich wiederum nicht beurteilen!
Ich weiß nur: (und das gilt für mich)

Das beste TaskSystem ist natürlich mein TaskSystem.
Direkt nach FreeRTOS.
Alle anderen hinken, zumindest habe ich noch kein "besseres" gefunden, sonst hätte ich dieses nicht bauen müssen.

Was mich wundert: Es gab niemanden hier, der zu einer vorhandenen Bibliothek wie z.B. TaskScheduler geraten hat...

Erstens:
Für meinen Geschmack sind da zu viele Haare dran.
Vielleicht passt sie an deinen Geist.
An meinen nicht.
Da müsste mich schon eine Notwendigkeit zu zwingen, mich damit zu beschäftigen.

Zweitens:
Dir wurde zu FreeRTOS geraten!
Aber das willst du ja aus irgendwelchen (absurden?) Gründen nicht.

--

und sich rasch ein Template für mich ergab...

Template ist ein Bezeichner mit einer eindeutigen Semantik in der C++ Welt.
Ich bitte dich, ihn nur für diesen Zweck zu verwenden.
Damit vermeidest du viel Verwirrungen.
Bei uns, und auch bei dir.

Es gab niemanden hier, der zu einer vorhandenen Bibliothek wie z.B. TaskScheduler geraten hat... das fand ich irgendwie unerwartet... ich dachte es wäre gerade sinnvoll, Bibliotheken zu nutzen und nicht alles jedes Mal neu zu "erfinden" - aber in Bezug auf asks liege ich da wohl weit ab der Praxis... ich hoffte auf "runter laden, INCLUDE, richtig anwenden, fertig!"

Der konkrete Anwendungsfall ist ja nur ein "Blinken" ... und genau der BlinkWithoutDelay Sketch aus den IDE Beispielen ist quasi die Mutter aller Sketche. An dem kommst imho nicht vorbei. Das musst verstehen lernen.
Bibliotheken sind toll (viele - nicht alle), deren Interfaces muss man aber auch kennen lernen. Viele User hier haben eigene Bibliotheken für Sachen die sie laufend / öfters brauchen, einige veröffentlichen ihre Sachen. ich glaube Die wenigstens schreiben alles selber - und wenn dann sind diese wohl kaum auf Arduino.cc zu finden.

Also es ist sicher nicht so, dass hier für oder gegen Bibliotheken gesprochen wird. Auf die Anwendung - auf den Mix kommt es an.

Danke. Ehrlich. Aber für meine Fragen fliegt Ihr mir zum Teil echt zu hoch...

combie:
Dir wurde zu FreeRTOS geraten!
Aber das willst du ja aus irgendwelchen (absurden?) Gründen nicht.

Herrje, habe ich nicht gesagt! Mir erschien es eingangs einfacher ohne, denn RTOS schien mir eine zusätzliche, höherer Anforderung. Daher formulierte ich lediglich, das ich keine Anforderung dafür habe. Wenn Ihr mir sagt: Das ist nicht nur besser, sonder auch einfacher, dann schaue ich mir das gerne an. Wenn nicht und ohne RTOS auch die Commmunity/Nutzerkreis in non-professional-Foren größer ist, dann ist RTOS für mich vermutlich der falsche Weg.

Mir scheint nach etwas Lesen für ESP8266 nun folgends zur Auswahl

  • Arduino-IDE (C++)
  • PlatformIO mit VSC (C++)
  • Sloeber/Eclipse (C++)
  • RTOS mit SDK/IDE-whatever? Das habe ich noch nicht konkrte/greifbar gelesen.
  • ESP-IDF mit konfigurierbarer Firmware; das scheint durchaus spannend, weil vermutlich ressourcen-Optimal, aber mit Lua (oder Python). Und mit welcher IDE habe ich auch noch nicht ganz verstanden.

-> Was davon ist Euer Rat für eine Anfänger, der durchaus Spaß daran hat, aber mehr am praktischen Ergebnis z.B. für Smarthome-Sensoren (z.B. den eCO2 aus BME680 heraus zu lesen) oder der Logik des Roboter (mit meiner Tochter, der vlt. auf die Lagesensoren Ihres smartphones reagiert), als die Schönheit des logik-tragenden Codes. Ich möchte nur durchaus strukuriert daran gehen und mir ein universelles Framework von Anfang an schaffen, dass ich non-spagetti auch noch in x Monaten lesen kann - das reicht mir.

Vielen Dank für Deine Einordnung zu den Bibliotheken, noiasca - das ist nachvollziehbar. Doch hierzu noch die Ergänzung...

noiasca:
Der konkrete Anwendungsfall ist ja nur ein "Blinken" ...

Ich habe Blinken eingangs als einfaches, konkrets Beispiel genannt, anhand dem ich mir konkrete Hilfe erhoffte - und ja auch bekam; testen muss ich das noch und begreifen. Vielleicht hilft es auch anderen, denn dafür sind Foren ja insbesondere da.

Es geht mir auch um Blinken, aber nicht nur. Morgen ist es ein Servo-Motor, der im Sekundentakt bestimmte Positionen an fahren soll, übermorgen whatever. Mein Ziel ist eine persönliches, universelles Framework für meine Bedarfe, dass ich 1x stricken möchte und dann nur noch anwenden aka. mit konkreten Aktionen ausstaffiere.

Vielmehr: Ich kämpfte ohne Erfolg damit, einen Task der vielen Beispielen genannten TaskScheduler-Library zu instanziieren mit eigenen Parametern, weil in den ganzen Beispielen (die ich dazu fand) nur x Task mit festen Parametern genutzt wurden aka. 2 Blink-Freuqenzen = 2 Tasks. Ganz viele "Mütter der Blink-Sketche" damit - konnte ich auch erfolgreich umsetzen, bevor ich mich hier anmeldete. Mein Ziel war aber zu verstehen wie ich 2 Blink-Frequenzen = 1 Task mit 2 Instanzen lösen kann. Da wird es dünn mit Beispielen. Ich habe schlicht noch nicht verstanden - aber meine Teste mit Eurem Input stehen auch noch aus - wie ich Parameter übergebe im Task-Kontext. Vielleicht nur eine Banalität für erfahrene C++/OO-Entwickler... für mich war es der Fels, der mich hier anmelden ließ.

Ja, vielleicht sind ja Eure - combies oder noiascas - Vorlage genau das Richtige für mich. Der Ball dazu liegt bei mir: Ich muss das die Tage testen und vor allem begreifen! :slight_smile:

Vielleicht gibt es aber auch parallel zu meinen Tests noch andere Meinungen und positive/negative Erfahrungen zu konkreten Bibliotheken - ein diveres Meinungsfeld dient üblicherweise ja allen und der Sache...

Tasks und Parameter:
Natürlich ist es so, dass eine Task (am Ende eigentlich auch nur eine Funktion) immer einen festen Satz Parameter hat. Das kann aber beispielsweise im Fall von combies Library auch gar keiner, einer oder mehrere sein.

Schau Dir da mal das Ampel-Beispiel an. Da gibt es zwei Tasks - Piepser und Ampel:

class Piepser : public Task
class Ampel: public Task // Ampelschaltung

Beide leiten von Task ab - das ist das ": public Task" und haben jeweils eigene Parameter, nämlich die Referenz auf das piepflag und bei der Ampel zusätzlich die Taktlänge. Das sieht man weiter unten in den Konstruktoren (hinter dem Doppelpunkt ist die Initialisierung der internen Variablen):

  public:
    Piepser(bool &piepflag):i(0),piepflag(piepflag){}
  ...
    Ampel(bool &piepflag,const unsigned long takt):piepflag(piepflag),takt(takt){}

Niemand hat etwas dagegen, wenn Du eine eigene Task mit zwei Blinkfrequenzen erzeugst:

class TwoBlinkFrequencies : public Task
{
  ...
  public:
    TwoBlinkFrequencies(const uint16_t freqLow, const uint16_t freqHigh){}

Was Deine Auflistung angeht:
Da wirfst Du im vierten Punkt leider das Mittel zur Code-Bearbeitung (IDE) und die Task-Lib durcheinander. Man kann RTOS-Tasks auf dem ESP8266 durchaus auch mit der Arduino-IDE oder den anderen erzeugen und bearbeiten. Das ist möglicherweise etwas beschwerlicher als bei den anderen (die ich aber nicht wirklich kenne oder intensiv ausprobiert hätte).

Ob am Ende für die Aufgabe "ich brauche verschiedene Funktionen in unterschiedlichen Taktungen" wirklich Tasks und ein Scheduler erforderlich sind, hängt vom Umfang der Aufgabe ab. Wie Du am Counter und Schrittmotor-Thread sehen kannst geht es auch ohne.

Ich würde dem TO empfehlen, erst mal die Grundlagen zu verstehen, incl. der schon genannten BlinkWithoutDelay, bevor er versucht eine EierlegendeWollMilchSau zu konzipieren.

Gruß Tommy

Mein Ziel ist eine persönliches, universelles Framework für meine Bedarfe, dass ich 1x stricken möchte und dann nur noch anwenden aka. mit konkreten Aktionen ausstaffiere.

Das ist eine Gute Idee.
Nur, vermute ich, dass du noch nicht so weit bist
Denn dann baust du ein auf deine Bedürfnisse angepasstes Tasksystem und deine Fragen lohnen sich nicht gestellt zu werden.

Vielleicht gibt es aber auch parallel zu meinen Tests noch andere Meinungen und positive/negative Erfahrungen zu konkreten Bibliotheken - ein diveres Meinungsfeld dient üblicherweise ja allen und der Sache...

Ich kann hier nicht für alle sprechen!

Es kann durchaus verschiedenen Meinungen zu einem Thema geben.
z.B. ich alleine, habe schon manchmal mehrere Meinungen zu einem Thema.

Beispiel:
Frage drei Imker nach ihrer Meinung zu einem speziellen Bienenproblem.
Du wirst 5 bis 10 Meinungen dazu hören, auch sich widersprechende sind dabei.
Und alle haben recht.

So sieht es hier auch aus.

Hallo,

ich kann Deine Wünsche ja nachvollziehen, dennoch warum willst Du von 0 auf 100 mit der Gefahr das Du Dich dabei überschlägst. Eierlegendewollmichsäue sind kompliziert und oft schlecht beherschbar. An dem Thema universell parametrierbare Software für alle möglichen Fälle haben sich schon ganze Heerscharen an Softis die Zähne ausgebissen.

Du hast ja geschrieben das Du noch nicht so lange dabei bist , dann sammele doch erst mal ein paar Erfahrungen mit der Mutter aller zeitlichen Abläufe (millis). Vieleicht stellst Du ja auch fest das, richtig und systematisch angewendet, damit eigendlich vieles möglich ist. Und für spezielle Sachen gibt es schliesslich auch fertigen libs. Beispiel LED-Streifen, Servomotoren, Schrittmotoren oder was auch immer.

Es wurde ja schon geschrieben das es sicher einige User hier gibt die sich für immer wiederkehrende Aufgaben eigene Funktionen oder Libs geschrieben haben. Habe ich auch gemacht, aus Spass an der Freude um was zu lernen. Basierend auf millis ist dabei eine Lib mit verschiedene Methoden entstanden. So können Blinker, cycle, delayon, delayoff und impuls Methoden verwendet werden, die man eigendlich in jedem Sketch benötigt. Im wesentlichen mit zwei Zeilen Code. Ohne das man jedesmal ein Konstrukt aus millis()-altzeit >=xxx verwendet. Natürlich wird es sowas auch irgendwo fertig geben. Ein Mitglied hier im Forum hat die Mobatools geschrieben und entwickelt die auch ständig weiter. Sowas für mich viel zu hoch, würde ich also nie selber machen.

Es mag also daran liegen das Dein Anliegen hier eine Empfehlung fü die beste Task lib zu bekommen für die meisten User hier nicht wirklich einem realen Bedarf entspricht. Es kann aber auch sein das wir alle was falsch machen, wer weiß.

Heinz

ard_work:
... aber es geht um eine grundsätzliche Frage. Mir erschien (mit meiner begrenzten Erfahrung) auch millis wie delay() der falsche Weg, weil in der Zeit anderer Prozesse gestört werden ...

Das erscheint mir tatsächlich die grundsätzliche Frage.

Ein Arduino mit ATmega328 hat einen Kern, kann also genau eine Aktion zur Zeit ausführen. Daher ist es wichtig, ein blockadearmes Programm zu entwickeln, das jeder Funktionalität die notwendige Zeit zuteilt. Soweit stimme ich mit Deinem Ziel überein.

Bei einem Arduino mit ATmega328 und seinen begrenzten Resourcen bin ich bislang ganz gut ohne TaskScheduler-Bibliothek ausgekommen, habe daher auch keine Erfahrungen sammeln können. Vermutlich geht es auch anderen hier im Forum Aktiven so, weshalb Du keine Antworten dazu bekommst. Bislang habe ich Interrupts für kurz anliegende Eingangssignale verwendet, das hat funktioniert. Der Aufwand für eine Taskverwaltung muß bezogen auf die verwendete Hardware mit berücksichtigt werden.

Ein Teensy 4.1 mit 600 MHz und mehr Speicher spielt da in einer ganz anderen Liga, der ESP8266/ESP32 ebenso. Das sind nicht nur rein rechtlich keine Arduinos mehr, sondern auch von der Leistung. Das hast Du ja selbst schon festgestellt. Für mich, der die Arduino-IDE gewohnt ist, stellt es sich als Segen heraus, wenn es fähige Menschen gibt, die auch diese Hardware damit zugänglich machen. Um meine LED-Animationen per WLAN und HTML-Seite parametrieren zu können, komme ich da relativ schnell zum Ziel.

Wenn ich mir allerdings die in der Arduino-IDE unmittelbar nicht lauffähigen Beispiele von espressif anschaue, dann ahne ich, daß ich bislang die vielfältigen Möglichkeiten nur angekratzt habe. Im Thema duty cycle messen eines PWM-Signals bei 20kHz habe ich mal so ein Beispiel für die Arduino-IDE umgeschrieben. Da findest Du Dinge, von denen Du hier schreibst.

Meine ganz persönliche Meinung: Behalte Dein Ziel im Auge, aber rüste gedanklich wie sprachlich ab. Nimm Dir eine konkrete Anwendung beispielsweise aus der Hausautomation und jage Meßdaten quer durchs Haus, die Du anzeigst, auch wenn Dein Haus auf dem Schreibtisch auf ein paar Zentimeter Draht schrumpft. Sammle Erfahrungen, lerne Deine persönlichen Vorlieben und Abneigungen kennen. Dann laß uns darüber austauschen.

Der ESP32 hat CAN-Bus eingebaut, braucht TJA1050 CAN Bus Tranceiver Modul, der UNO/Nano braucht ein MCP2515 CAN Bus Modul. Der ESP8266 benötigt ein spezielles CAN MODUL für 3,3 V Logikspannung.

Rentner:
Es kann aber auch sein das wir alle was falsch machen, wer weiß.

Wohl war ::slight_smile: