Hilfe bei der Umsetzung eines Shotspenders!

Neue Frage:
Hallo Freunde,
ich möchte als Geschenk für einen Freund einen Shotspender selbst programmieren, den er mir mal auf social Media gezeigt hat und toll fand. Ich sende den Link mal mit, damit ihr euch besser vorstellen könnt um was es geht: https://www.instagram.com/reel/CprbM-1oehu/?igshid=MDJmNzVkMjY=
Jedoch benutze ich lediglich 2 Endtaster, einen Servo-Motor, eine REB-LED zur Beleuchtung des Fahrerhauses und eine 5V Pumpe, welche ich über ein L298 (Motor Controller für 2 Motoren mit PWM, ich benutze ihn jedoch nur für die Pumpe) ansteuere.
Nun zum Problem: Es hat einmal funktioniert, doch wenn ich nun einen Taster drücke, fährt der Servo zum jeweiligen Glas (auch schön an der Farbe des Lichtes zu erkennen, beim einen Glas wird es blau, beim anderen rot), doch sobald die Pumpe schalten möchte scheint das ganze System zu resetten und der Servo fährt zurück zur Startposition.
Ich weiß, dass ein Arduino bei zu viel Strom "abschaltet", um sich zu schützen. Aber ist das überhaupt das Problem und wie könnte ich den Arduino weniger belasten? Ich habe nämlich schonmal ein Relais getestet, hat aber auch nicht funktioniert. Das Schaltplan-Programm hatte solche Motor Controller nicht, deshalb habe ich es mit einem Relais gezeichnet. Die Widerstände passen auch nicht, aber ich hoffe ihr könnt darüber hinwegsehen. Ich verzweifle, bitte helft mir!

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position

int Servo = 9;

int Pumpe = 11;

int Pumpzeit = 10000;

int Lichtzeit = 500; //Zeigt an wie lange die einzelnen Farben leuchten sollen

int Taster1 = 13; //Taster Pin
int Taster2 = 12; //Taster Pin

bool Status1 = 0; //Status, ob Taster gedrückt ist oder nicht
bool Status2 = 0; //Status, ob Taster gedrückt ist oder nicht

bool ObGeradeVoll1 = 0; //Soll speichern, ob Glas gerade voll ist oder nicht, dass wenn ein Glas länger auf dem Schalter steht, es nicht dauerhaft befüllt wird
bool ObGeradeVoll2 = 0; //Soll speichern, ob Glas gerade voll ist oder nicht, dass wenn ein Glas länger auf dem Schalter steht, es nicht dauerhaft befüllt wird



int Pos1 = 40; //Servo Positionen für die jeweiligen Gläser
int Pos2 = 90;

unsigned long Zeit1 = 0; //Soll später mit millis -Befehl schauen, welches Glas als erstes abgestellt wurde
unsigned long Zeit2 = 0;

int r = 6; //RGB- Farbpins
int g = 5;
int b = 7;

int i = 0; //unwichtige Variable wie oft LEDs blinken sollen


void setup() {

  Serial.begin(9600);

  pinMode(Servo, OUTPUT);
  pinMode(Pumpe, OUTPUT);
  pinMode(r, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(b, OUTPUT);

  pinMode(Taster1, INPUT);
  pinMode(Taster2, INPUT);

  myservo.attach(Servo);  // attaches the servo on pin 9 to the servo object

  digitalWrite(Pumpe, 0);

}

void loop() {

label:

 digitalWrite(g, HIGH);

Status1 = digitalRead(Taster1);
Status2 = digitalRead(Taster2);

 Zeit1 = 0;
 Zeit2 =0;


  if(Status1 == HIGH && ObGeradeVoll1 == 0)
  {
    Zeit1 = millis(); //Zeit seit Beginn des Programms wird gespeichert, um zu sehen welches Glas wann auf die Taster gestellt wurde
  }

  if(Status1 == LOW)
  {
    ObGeradeVoll1 = 0; //Wenn das Glas vom Taster ist, soll der Status des vollen Glases wieder zurückgesetzt werden
  }

  delay(200);

  if(Status2 == HIGH && ObGeradeVoll2 == 0)
  {
    Zeit2 = millis(); //Zeit seit Beginn des Programms wird gespeichert, um zu sehen welches Glas wann auf die Taster gestellt wurde
  }

  if(Status2 == LOW)
  {
    ObGeradeVoll2 = 0; //Wenn das Glas vom Taster ist, soll der Status des vollen Glases wieder zurückgesetzt werden
  }

  Serial.print("Erstes Glas:");
  Serial.println(ObGeradeVoll1);
  Serial.print("Zweites Glas:");
  Serial.println(ObGeradeVoll2);

  if(Zeit1 > 0 && Zeit2 == 0 && ObGeradeVoll1 == 0)
  {
  digitalWrite(g, LOW);
  digitalWrite(b, HIGH);

    myservo.write(Pos1);              // tell servo to go to position in variable 'pos'
  


    delay(1000);
    digitalWrite(Pumpe, 1);
    delay(Pumpzeit);
    digitalWrite(Pumpe, 0);

  ObGeradeVoll1 = 1;
  i = 0;

  digitalWrite(b, LOW);
goto label;
  }
   
  if(Zeit2 > 0 && Zeit1 == 0 && ObGeradeVoll2 == 0)
  {
  digitalWrite(g, LOW);
  digitalWrite(r, HIGH);

    myservo.write(Pos2);              // tell servo to go to position in variable 'pos'
    delay(1000);
    digitalWrite(Pumpe, 1);
    delay(Pumpzeit);
    digitalWrite(Pumpe, 0);

  ObGeradeVoll2 = 1;
  i = 0;

  digitalWrite(r, LOW);
goto label;
  }


  if(Zeit1 < Zeit2 && Zeit1 != 0 && Zeit2 !=0 && ObGeradeVoll1 == 0 && ObGeradeVoll2 == 0)
  {
  digitalWrite(g, LOW);
  digitalWrite(r, HIGH);

    myservo.write(Pos2);              // tell servo to go to position in variable 'pos'
    delay(1000);
    digitalWrite(Pumpe, 1);
    delay(Pumpzeit);
    digitalWrite(Pumpe, 0);

  ObGeradeVoll2 = 1;
  i = 0;

    digitalWrite(r, LOW);
goto label;
  }

   if(Zeit2 < Zeit1 && Zeit1 != 0 && Zeit2 !=0 && ObGeradeVoll1 == 0 && ObGeradeVoll2 == 0)
  {
  digitalWrite(g, LOW);
  digitalWrite(b, HIGH);

    myservo.write(Pos1);              // tell servo to go to position in variable 'pos'
    delay(1000);
    digitalWrite(Pumpe, 1);
    delay(Pumpzeit);
    digitalWrite(Pumpe, 0);

  ObGeradeVoll1 = 1;
  i = 0;

  digitalWrite(b, LOW);
goto label;
  }


}

Ob Dein GOTO da so Sinn macht, bezweifel ich mal.
Ich denke Du suchst eine Schrittkette.
Ich überleg noch, wie man das am besten mit dem lebeneden Objekt beibringt....

PS: Die Transistoren ohne Basiswiderstand und einen gemeinsamen R auf dem Kollektor ist auch nicht gerade Stand der Technik....

Und Deine Taster sind eigenartig verdrahtet - wenn die tatsächlich so angepinnt sind, stehen die auf Dauer LOW.

erstmal keine Verbraucher anschließen, auch wenn es 5V heisst. guck wo du Relay angeschlossen hast.

was ist es dreipoliges mit dem "S" markiert?

Die Widerstände vom Taster spendiere den LED, im Sketsch machst du im Setup

 pinMode(Taster1, INPUT_PULLUP);
 pinMode(Taster2, INPUT_PULLUP);

Es wird nach LOW abgefragt .
Lange wird der D12 nicht leben, Relais schaltet man über Transistor dazu noch eine Diode Antiparallel zu Spule, zB eine 1N4007 .
Was für Servo ist das, verträgt er 9V?
Warum nimmst du PNP Transistoren?

Servo ? :wink:

Servo

Okay, das mit den Transistoren nehm ich mir zu Herzen, wobei das ja eigentlich nur das Licht betrifft und so ziemlich als einziges funktioniert​:joy::see_no_evil: Zu den Tastern, die habe ich nicht direkt so parallel geschaltet wie im Schaltplan, sondern jeder einzeln an Plus und Minus, aber das dürfte ja keinen Unterschied machen. Das sind jeweils ein Pull down resistor und wenn der Schalter gedrückt wird, ist der Eingang positiv

Wie kann ich das mit den Tastern dann eleganter lösen?
Bei der Pumpe habe ich tatsächlich eine Diode Antiparallel eingebaut.
Es ist ein ganz normaler 9g Servo.
Upsi, müsste mich vertan haben, ich hab's mit Transistoren nicht ganz so, also sie schalten wenn positive Spannung anliegt.

1 Like

Ist 5V Servo (Operating voltage: 4.8V), wen so einer:

plannst du 9V Batterie nutzen oder was ?

Die Transistoren funktionieren so nicht.
BJT Transistoren brauchen immer einen Basiswiderstand.
Du kannst einen PNP der an 9V hängt nie mit 5V an der Basis ausschalten.
Nimm NPN mit Basiswiderständen und schalte die zwischen Last und Masse.
Du kannst auch nicht Taster an Masse schalen und Pulldown-Widerstände benutzen. Taster entweder auf +5V oder der Widerstand.
Jede Einzelne LED braucht ihren strombegrenzungswiderstand.
Ein relais kannst Du nicht direkt an einen Ausgang anschließen. Da braucht es immer einen Transistor und Schutzdiode.

1 Like

Ein Schaltplan, der nicht das zeigt was Du tatsächlich aufgebaut hast, ist sinnlos. Da sind sicher noch mehr Fehler drin, denn so wie das gezeichnet ist, würde nichts funktionieren und der Arduino wäre schon gestorben.
Im Zweifelsfall nimm einfach ein Blatt Papier und einen Stift um deinen Schaltplan zu zeichnen. Und dann ein ordentliches Foto davon hier einstellen.

In der Zeit, wo ihr Schaltungsfragen klärt, dachte ich mir einfach mal nen netten Code in den Raum zu werfen, nachdem ich ja den ausgangscode als nicht optimal eingestuft habe :wink:
Meiner ist es sicher auch nicht, aber evtl. sieht man, worauf es rausläuft.

Für die Hardware:
Taster LOW-Aktiv
Led's HIGH-Aktiv
Pumpe HIGH-Aktiv (bei Verwendung einer hilfsweisen H-Brücke DIR fest verdrahten und EN dann an den Pumpenpin)
Die Vorgaben der Pins und Servopositionen übernommen.
Ich hätte das ganze vielleicht noch ein wenig anders gemacht - rein aus Showeffekten - aber das geht evtl. später auch noch.

was der Sketch machen soll:
Ohne aufgestelltes Glas leuchtet die blaue LED
Es wird der Kontakt abgefragt.
Ein leeres aufgestelltes Glas lässt die LED verlöschen und startet die Befüllung.
Dabei wird zuerst die Position mit dem Servo angefahren, dann eine Pause eingelegt und dann befüllt.
Während der Befüllung blinkt die LED zum Glas.
Ist die Pumpzeit abgelaufen, wird die LED zum Dauerleuchter. und die blaue LED beginnt wieder zu leuchten.

Wird nach der Erkennung des eingestellten Glases das Ding vor dem vollständigen befüllen rausgenommen, geht die Pumpe aus und so weiter...

Der Blinker läuft mit modulo. Das ist beabsichtigt und funktioniert so auch.

Ich hoffe nix übersehen zu haben.
kompiliert fehler- und warnungsfrei

// Forensketch shotspender
// https://forum.arduino.cc/t/hilfe-bei-der-umsetzung-eines-shotspenders/1138419/14

#include <Servo.h>
Servo myservo;

constexpr byte shots {2};
constexpr byte servoPin {9};
constexpr byte pumpePin {11};
constexpr uint32_t pumpZeit {10000};
constexpr uint32_t servoZeit {1000};
constexpr byte bluePin {7};

byte aktiveShot = 0;

enum class STATUS {auswahl, warten, fuellen, entnehmen};
STATUS status = STATUS::warten;

struct SHOT
{
  const byte tasterPin;
  const byte ledPin;
  const uint16_t servoPos;
  uint32_t startTime;
  bool isFull;
};

SHOT shot[shots] =
{
  {13, 6, 40, 0, false},
  {12, 5, 90, 0, false},
};


uint32_t startTime;

void setup()
{
  Serial.begin(9600);
  Serial.println(F("Start..."));
  pinMode(servoPin, OUTPUT);
  myservo.attach(servoPin);
  pinMode(pumpePin, OUTPUT);
  digitalWrite(pumpePin, LOW);
  pinMode(bluePin, OUTPUT);
  digitalWrite(bluePin, HIGH);
  for (byte b = 0; b < shots; b++)
  {
    pinMode(shot[b].tasterPin, INPUT_PULLUP);
    pinMode(shot[b].ledPin, OUTPUT);
    digitalWrite(shot[b].ledPin, LOW);
  }
}

void loop()
{
  if (status != STATUS::auswahl &&                          // im laufendem Programm
      status != STATUS::entnehmen)
  {
    if (digitalRead(shot[aktiveShot].tasterPin))            // Glas entnommen
    {
      status = STATUS::entnehmen;                           // Ende festsetzen
    }
  }
  fillShot();
  checkFull();
}
//
void fillShot()
{
  switch (status)
  {
    case STATUS::auswahl:
      if (aktiveShot >= shots)                              // Begrenzung
      { aktiveShot = 0; }
      if (!digitalRead(shot[aktiveShot].tasterPin))         // Taste ausgelöst
      {
        if (!shot[aktiveShot].isFull)                       // nicht gefüllt
        {
          digitalWrite(bluePin, LOW);
          myservo.write(shot[aktiveShot].servoPos);         // Servo einstellen
          shot[aktiveShot].startTime = millis();            // StartZeit merken
          status = STATUS::warten;                          // nächster Schritt
        }
      }
      else
      { aktiveShot++; }                                      // nächste Position vorauswählen
      break;
    case STATUS::warten:
      if (millis() - shot[aktiveShot].startTime > servoZeit) // kurze Pause
      {
        shot[aktiveShot].startTime = millis();
        digitalWrite(pumpePin, HIGH);
        status = STATUS::fuellen;
      }
      break;
    case STATUS::fuellen:
      blink(aktiveShot);                                     // blinkt während Füllvorgangs
      if (millis() - shot[aktiveShot].startTime > pumpZeit)  // Pumpzeit abgelaufen
      { status = STATUS::entnehmen; }
      break;
    case STATUS::entnehmen:
      digitalWrite(pumpePin, LOW);                           // aus
      digitalWrite(bluePin, HIGH);                           // Frei
      digitalWrite(shot[aktiveShot].ledPin, HIGH);           // :)
      shot[aktiveShot].isFull = true;                        // Merken
      aktiveShot++;                                          // nächste Voreinstellung
      status = STATUS::auswahl;                              // fange an von vorn
      break;
  }
}
//
void checkFull()
{
  for (byte b = 0; b < shots; b++)
  {
    if (shot[b].isFull &&                          // Nur wenn voll UND
        digitalRead(shot[b].tasterPin))            // Glas steht nicht mehr drauf
    {
      shot[b].isFull = false;
      digitalWrite(shot[b].ledPin, LOW);           // zwangsweise aus machen
    }
  }
}

//
void blink (const byte num)
{
  digitalWrite(shot[num].ledPin, (millis() / 500) % 2);
}

Wow, das ist ja unglaublich :hushed: Wo habt ihr gelernt so zu programmieren? Ich werde gleich mal probieren dem Programmcode folgen zu können​:joy:

Naja, erstmal heisst es die Logik aufzulösen.
Alles weitere hier mitgelesen und immer wieder probiert.
Ab und an auch ins Klo greifen und Schelte abholen gehört aber auch dazu.

Mein Einstieg war i.Ü. ein pdf zum Download, welches ich jedem nur empfehlen kann. Einfach abends immer mal ein paar Seiten lesen und dann drüber schlafen (Ich habs an 4 Abenden durch gehabt) Dann weisst, was drinnen steht und kannst ggfls. nachschlagen.

Alles andere ergibt sich. :slight_smile:
Und wenn Du ein paar Mal etwas gebastelt hast, kannst das auch....

2 Likes

so Is es :wink:

Also nach der Umsetzung eurer Tipps (Basiswiderstände an den Transistoren der LEDs, den Tastern auf Low und mit internen Pullups und dem neuen Programmcode), bewegt sich der Motor jede Sekunde minimal. Das Licht leuchtet aber ganz schwach und man merkt, dass sich der Arduino schwer tut. Ich würde euch gerne ein Video davon zeigen, aber das kann ich leider nicht hochladen. Ich habe im Moment keine Transistoren mehr, sonst würde ich mal probieren den Servo und den Motor Controller über Transistoren laufen zu lassen. Habt ihr noch Tipps oder heißt es jetzt einfach ausprobieren?
PS: ich hätte noch einen Arduino mini, auf den ich zurückgreifen könnte. Macht das einen Unterschied zum Arduino UNO oder sind die quasi identisch?

Bevor Du anfängst mit dem Servo und der Pumpe, würde ich nur die Tasten für die Gläser und die LED's ausprobieren. Da es sich hier nur um zeitlich gesteuerte Dinge handelt, müssen die auch so laufen.

Parallel dazu könnte man Ausgaben auf dem SerMon generieren.
Wenn ich soll, musst was sagen. Dann bau ich da was ein, ohne das Dir der SerMon gefloodet wird.

Sollten die LED's dann mit der Ausgabe übereinstimmen, kannst weiter machen mit dem Servo.
Welcher Motor zuckt? Der von der Pumpe oder der vom Servo?

Licht funktioniert einwandfrei wie du es beschrieben hast. Die Pumpe zuckelt nur sehr schlecht und ohne Pumpe funktioniert der Servo, doch mit Einschalten der Pumpe spinnt der Servo auch ein bisschen (fährt teilweise während des Befüllungsvorganges an die Anfangsposition, also als würde der Arduino abstürzen)