"X" Motoren "X" Sekunden unabhängig steuern

Moin moin,
habe letzten hier schon ein post gemacht der mich auch schon ein stück weiter gebracht hat.
Ich bin nun wieder auf ein Problem gestoßen und versuche nun mein vorhaben ein wenig Genauer zu beschreiben.

Zum Projekt:
Ich baue gerade an einer Cocktailmaschine, ich habe dafür 5 Schlauchpumpen besorgt die ich nun mit Transistoren über den Arduino ansteuern möchte. Soweit so gut.

Zum Problem:
Ich habe nun in den Arduino über ein Array, ein Rezept eingespeichert(sollen später mehr werden.).
ich möchte nun wenn ein Knopf gedrückt wird der für ein Rezept steht eine Funktion aufgerufen(angedeutet mit der Funktion void pump, welche bis jetzt nur die zeit ausrechnet.) mit dem Rezept als Parameter. Soweit auch kein problem, aber die pumpen müssen jetzt unterschiedlich lange, möglichst gleichzeitig gesteuert werden.
Kann mir da wer helfen?

//Edit:
Ich weiss ich bin kein programmier Profi, können also Fehler vorkommen.
Zum Code:

//BoozeBot by Torben Friedel (2015)
// This is a program for a Cocktail bot. It consists of 5
// peristaltic pumps(12V).
//




  const int pumps = 5; //Number of Pumps
  int pumpPins[pumps] = {1,2,3,4,5};//Pins of the pumps (erstmal nur ein Platzhalter)
  float plantersPunch[pumps] = {1.5, 2.0, 5.0, 1.3,0.0};//First Cockail amount of each liquid in mL(auch nur Platzhalter und nicht repräsentativ) 
  float timings[pumps];//for the individual time each pump needs for the ingredient
  bool pStatus[pumps] = {0,0,0,0,0,}; //Status of each pump if its on or of(kann überflüssig sein)
  
  const float timing = 2.5 ; //The time the pump needs to dispense 1 ml.



void setup() {

Serial.begin(9600);
}

void pump(float cocktail[pumps]) 
{
//Calculate time needed for the pump to pump the liquid and stored in array timings
  for(int i = 0; i <= pumps; i++)
  {
    
    float Time = (cocktail[i]/timing)*1000 ;
    Serial.println("");//New Line for a better overview 
    Serial.println(i);//current loop count
    
    Serial.println(Time);//the time calculated in millis on line 25
    long currentMillis = millis();

    timings[i] = Time;    

    
  }
  
  
  for(int i = 0; i <= pumps; i++)
  {
    if(pStatus[i] == 0)
      {
        
        
      }
    
  }
  memset(timings, 0,sizeof(timings));
}
void loop() {
  pump(plantersPunch);

  delay(2000);

}

Vorschlag:

Du machst dir eine Klasse "Zutat"
Dann baust du dir ein Array mit Zutat Objekten.
Du sagst der jeweiligen Zutat, wie viel sie liefern soll.

Wenn alle Zutaten glücklich/abgelaufen sind, kannst du den Becher entnehmen.

delay(2000);

Delay ist verboten.

combie:
Vorschlag:

Du machst dir eine Klasse "Zutat"
Dann baust du dir ein Array mit Zutat Objekten.
Du sagst der jeweiligen Zutat, wie viel sie liefern soll.

Wenn alle Zutaten glücklich/abgelaufen sind, kannst du den Becher entnehmen.

Danke für die Antwort, ist ja aber schon Ähnlich zu dem wie ich es jetzt habe, und wie ich es lese willst du es nacheinander abarbeiten, was zu lange dauern würde 40mL/min.

Das geht schon so ähnlich mit Arrays, for-Schleifen und millis()

Du darfst aber kein delay() machen. Sondern musst ständig abfragen ob die vorgegebene Zeit abgelaufen ist

Serenifly:
Das geht schon so ähnlich mit Arrays, for-Schleifen und millis()

Du darfst aber kein delay() machen. Sondern musst ständig abfragen ob die vorgegebene Zeit abgelaufen ist

Genau, das war der Plan nur reicht mein gehirnschmalz nicht ganz aus, denn ich komme nicht auf einen ansatz.

Dann lese und verstehe erst mal: "Blink without delay"

und wie ich es lese willst du es nacheinander abarbeiten, was zu lange dauern würde 40mL/min.

Nein!
Da hast du mich falsch verstanden.

Etwas Nahrung für Dein Gehirnschmalz:

#define PUMPEN 5   // Number of Pumps
#define REZEPTE 9  // Anzahl der Rezepte
const unsigned int zeiten[REZEPTE][PUMPEN] = {1500, 2000, 5000, 1300,    0,    // Planters Punch
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500,    // Nix Mix
                                              2500, 2500, 2500, 2500, 2500     // Nix Mix
                                             };  // amount of each liquid in ml
const byte pumpPins[PUMPEN] = {2, 3, 4, 5, 6}; //Pins of the pumps (erstmal nur ein Platzhalter)
const byte startPin = 8;
const unsigned int durchfluss = 2500; //The time the pump needs to dispense 1 ml in ms
unsigned long aktMillis, pumpeMillis[PUMPEN];
bool aktStart, altStart;
byte rezept, pumpe;

void setup() {
  Serial.begin(9600);
  Serial.println("Programmanfang, bitte Rezeptnummer einstellig eingeben.");
  for (byte i = 0; i < PUMPEN; i++) {
    pinMode(pumpPins[i], OUTPUT);
  }
  pinMode(startPin, INPUT_PULLUP);
  aktStart = digitalRead(startPin);
  altStart = aktStart;
}

void loop() {
  if (Serial.available()) {
    char eingabe = Serial.read() - 49;
    if ((eingabe >= 0) && (eingabe < REZEPTE)) {
      rezept = eingabe;
      Serial.print("Gewaehlte Rezeptnummer: ");
      Serial.println(rezept + 1);
    }
  }
  aktMillis = millis();
  altStart = aktStart;
  aktStart = digitalRead(startPin);
  if (!altStart && aktStart) {
    delay(30);
    for (byte i = 0; i < PUMPEN; i++) {
      digitalWrite(pumpPins[i], HIGH);
      pumpeMillis[i] = aktMillis;
    }
      Serial.print("Rezeptnummer ");
      Serial.print(rezept + 1);
      Serial.println(" wird gemixt.");
  }
  if (aktMillis - pumpeMillis[pumpe] >= zeiten[rezept][pumpe]) {
    digitalWrite(pumpPins[pumpe], LOW);
  }
  pumpe++;
  pumpe = pumpe % PUMPEN;
}

Bei mir würde das dann her so aussehen:

class Handler
{
  protected:
  static Handler* first;
  Handler* next = NULL;
  
  Handler()
  {
    if(first) next = first;
    first = this;
  }
  
  virtual bool update() = 0;
  
  public:
  static bool handle()
  {
      Handler* temp = first;
      bool bereit = true;
      while(temp)
      {
        bereit = bereit && temp->update();
        temp = temp->next;
      }
      return bereit;
  }
};
Handler *Handler::first = nullptr;


class Zutat : public Handler 
{
  private:
  enum ZUSTAND {Z_Start, Z_Pumpen} zustand = Z_Start;
  unsigned long pumpzeit;
  unsigned long startzeit;
  byte pin;
  

  virtual bool update() // liefert true, wenn bereit
  {
    if(zustand == Z_Pumpen)
    {
      if(millis() - startzeit > pumpzeit)
      {
        digitalWrite(pin,0);
        zustand = Z_Start;
      } else return false;
    } 
    return true;
  }
  
  public:
  Zutat(byte pin) : pin(pin) // Konstruktor
  {
    pinMode(pin,OUTPUT);
    digitalWrite(pin,0);
  } 
  
  void menge(unsigned long zeit)
  {
    pumpzeit  = zeit;
    startzeit = millis();
    zustand = Z_Pumpen;
    digitalWrite(pin,1);  
  }
} ;



//----------------------------------------------



const byte taster       = 12; // Taster Pin
const byte bereitschaft = 13; // BereitschaftsLED


// hier könnte man schön ein Array draus machen.
Zutat Rum(2);     // Pumpe an pin 2
Zutat Tee(3);     // Pumpe an pin 3
Zutat Zitrone(4); // Pumpe an pin 4


void macheGrog()
{
  // diese Daten dürfen auch aus einem anderen Array stammen
  Rum.menge(1200); // 1200ms
  Tee.menge(8000); 
  Zitrone.menge(1000);
}




void setup() 
{
   pinMode(taster,INPUT_PULLUP);
   pinMode(bereitschaft,OUTPUT);
   digitalWrite(bereitschaft,0);
}

void loop() 
{
  bool bereit = Handler::handle();  
  digitalWrite(bereitschaft,bereit); // Zeige Bereitschaft (pin13 led)
  if(bereit && !digitalRead(taster))  macheGrog();
}

Auch wenn ich nicht OOP mache, wollte ich mal einen Versuch starten, bekomme aber "'nullptr' was not declared in this scope".

bekomme aber "'nullptr' was not declared in

Dann benutzt du vermutlich noch nicht die 1.6.7 ....

Ersetze nullptr durch NULL, dann sollte das gelingen.

IDE 1.6.5 :frowning:

Mit NULL ist der Grog fertig, allerdings 1 Sek Zitrone, je 8 Sekunden Grog und Tee. Die Mischung ist mir zu stark :o

nullptr geht auch in 1.6.5. Aber man muss C++11 extra aktivieren

Geh nach x:\Arduino\hardware\arduino\avr\platform.txt und hänge bei compiler.cpp.flags -std=gnu++11 an

Dann gehen auch viele andere sehr nützliche Dinge :slight_smile:

Nun mag meine IDE 1.6.5 auch nullptr! Danke!

Die Mischung ist aber immer noch zu stark! :confused:

Die Mischung ist aber immer noch zu stark!

Du meinst, ich habe da einen Fehler drin?

:wink: Tja, dann betrachte das Programm mal als Suchbild... :wink:

Ich komme heute nicht mehr zur Fehlersuche.....

Ein Blick auf die Uhr sagt :sleeping:

Wow!
Da hast du mich auf ein lustiges Problem hingewiesen!!!

Nach einigen Tests, kann ich noch keine Ursache vorweisen, aber das Problem jetzt beschreiben.

Beispiel:

// Testcode, nicht trinken!
void macheGrog()
{
  Rum.menge(3000);
  Tee.menge(2000); 
  Zitrone.menge(1000);
}

So gehts.

Offensichtlich hat die Reihenfolge der Zutaten einen Einfluss auf die Fehlfunktion.

Da der Quellcode quasi identisch ist, vermute ich mal einen Compiler/Linker Fehler.
Oder sieht jemand einen Fehler in meinem Quellcode?

@Serenifly
Hülfe!

Wieso ich? :frowning: Ich hätte das einfach mit Arrays und for-Schleifen gemacht. Du wolltest es schön, aber kompliziert.

Wieso ich?

Gute Frage!
Vielleicht, weil ich dir zutraue den Bock, den ich da (evtl) schieße, zu finden.

Ich hätte das einfach mit Arrays und for-Schleifen gemacht.

Eine Schleife, habe ich da auch drin!

Gut!
Es gibt viele Wege nach Rom.
Aber warum gerade hier solche Hürden auftauchen, ist mir noch nicht klar.

Ich habe mir mal Serial Ausgaben eingebaut, aber wo der Fehler liegt sehe ich so auch nicht.

Was man beachten muss ist dass in der verketteten Liste das letzte Element immer vorne eingehängt wird und so zuerst bearbeitet wird. Es geht dann wenn die Zeit in absteigender Reihenfolge angegeben werden (bzw. in aufsteigender Reihenfolge bearbeitet werden). Also z.B.:

2 Start: 5613
3 Start: 5613
4 Start: 5614

4 Ende: 6615, Zeit: 1001
3 Ende: 7614, Zeit: 2001
2 Ende: 8114, Zeit: 2501

Aber wenn z.B. 4 eine höhere Zeit ist, habe allen anderen Objekte auch diese Zeit. Und wenn 3 die höchste Zeit ist, dann hat 2 auch diese Zeit.

Ich habe mir mal Serial Ausgaben eingebaut, aber wo der Fehler liegt sehe ich so auch nicht.

Danke!
Und: Geht mir auch so...

So ein Defekt, ist mir in der AVR Welt noch nicht unter gekommen.
Habe ich gedacht.....
Und es mit dem DUE gegen getestet....
Das selbe (Fehl) Verhalten.

Ich werde das später mal ganz genau untersuchen.