Automatischer Weindispenser

Hallo, ein Freund von mir hat begonnen einen automatischen Weineinschenker zu bauen und er hat mich gebeten ihm ein wenig zu helfen. Jedoch haben wir uns beide beim Arduino programmieren ein wenig überschätzt. Der Weineinschenker ist ein Gerüst, dass von einem DC-Motor angetrieben wird. Auf dieses Gerüst kann man eine 9l Flasche hineinlegen. Es gibt auch noch ein Display mit einem Arduino Mega 2560 R3 auf dem man als erstes eingibt, ob man ¼ oder 1/8 eingeschenkt bekommen haben will. Vor dem Gerüst befindet sich eine Waage auf dem das Glas steht, diese wiegt ab wie viel schon drin ist und stoppt, wenn der Wert, den man ausgewählt hat erreicht ist.

Das Problem ist jetzt, dass es nicht richtig einschenkt, deshalb brauchen wir eine Glasverschiebung mithilfe einer Linearachse. Und zwar würde es sich mit drei Verschiebeschritten ausgehen, dass es immer richtig einschenkt. Das Gerüst wird wie gesagt von einem Motor angetrieben und es soll sich bei jedem Einschenkvorgang zurückdrehen, bis es bei den Endschaltern ansteht, dann dreht es sich wieder nach vorne, so lange bis die Waage stopp sagt. Bei der eingesetzten Flasche, soll bei jedem Einschenkvorgang der Wert, der ausgeschenkt wird abgezogen und gespeichert werden. Dann soll sich je nach der Menge, die noch in der Flasche ist, das Glas passend zu der Weinflasche mitbewegen.

Zum Display: es muss am Anfang noch irgendwie abgefragt werden, ob eine neue Flasche eingesetzt wird und es muss wie oben schon erwähnt immer mitgezählt werden wie viel noch drinnen ist.

Außerdem hätten wir auch gerne noch einen Feuchtigkeitssensor irgendwo eingebaut, falls trotzdem mal was daneben geschüttet wird und dazu soll, dann eine Meldung auf dem Display ausgegeben werden.

Unsere Probleme noch einmal aufgelistet:

Glasverschiebung

Menge der Flasche immer wieder abspeichern

Neue Flasche eingeben

Feuchtigkeitssensor mit Meldung am Display

Es würde uns wirklich sehr weiterhelfen, wenn ihr dazu Ideen hättet oder vielleicht sogar schon so ähnliche Programmteile, die ihr uns zeigen könntet. Ich habe Fotos, Videos und Programme angefügt.

Danke schonmal im Voraus!

  • Steuerprogramm:
const int Motor_CLK=2;// wird zum Erzeugen von Interrupts mithilfe des CLK-Signals verwendet
const int Motor_DT=3;// wird zum Lesen des DT-Signals verwendet
int lastCount=0;// verfolgt den letzten Drehwert
volatile int virtualPosition=0;// wird aktualisiert durch die ISR (Interrupt Service Routine)
int lastsavePosition=0;                                                                                //Variablen Deklaration
int Einschenkvorgang=1;
int currentPage=0;
int viertal=0;
int achterl=0;
int gewuenschteMenge=0;
int bedingung_rechtslauf_1_1=0;
int Schluessel=0;
int pwmOutput=0;
int Schluessel2=0;
int buttonPinWert=0;
int Schluessel3=0;
int empfangen=0;
unsigned long Zeit=0;
unsigned long Zeit2=0;
unsigned long deltat=0;
int Gewicht=0;
int Gewicht2=0;
int deltag=0;
int nachstellP=0;
int firstsaveposition=0;
int Schluesselfirstsaveposition=0;
int bedingung_linkslauf_1_2_zusatz=0;
int Richtung=0;
int Istwert=0;
int Sollwert=0;
int Ablauf=0;
int bedingung_linkslauf_2_1_zusatz=0;
int Glas_weg=0;
int Glas_voll=0;
int S=0;
int Sicherheit=0;




// ------------------------------------------------------------------     ENCODER

// INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT      ENCODER                      unterbricht Aktivität des Prozessors und sorgt dafür, dass eine andere Funktion ausgeführt wird

// ------------------------------------------------------------------     ENCODER
void isr ()                                                             //ENCODER
{                                                                       //ENCODER
  static unsigned long lastInterruptTime = 0;                           //ENCODER
  unsigned long interruptTime = millis();                               //ENCODER
                                                                        //ENCODER
    if (digitalRead(Motor_DT) == LOW)                                   //ENCODER
      {                                                                 //ENCODER
        virtualPosition++ ;                                             //ENCODER
      }                                                                 //ENCODER
    else                                                                //ENCODER
   {                                                                    //ENCODER
      virtualPosition-- ;                                               //ENCODER
   }                                                                    //ENCODER
   lastInterruptTime = interruptTime;                                   //ENCODER
}                                                                       //ENCODER
// ------------------------------------------------------------------     ENCODER

// INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT     INTERRUPT      ENCODER

// ------------------------------------------------------------------     ENCODER
#include "HX711.h"//HX711
#include "OneButton.h"
#define calibration_factor -3610// This value is obtained using the SparkFun_HX711_Calibration sketch          
#define DOUT 4                                                                                               
#define CLK 5                                                                                              
#define enA 11                                                                                               
HX711 scale;                                                                                               
int speed=10;            
int in2=8;          
const int IN2=8; 
int in1=9;             
const int IN1=9;    
const int buttonPin=7;    
const int buttonPin2=6;   
int butState = LOW;         
OneButton button(buttonPin, false);               




void setup() 
{
  pinMode(enA, OUTPUT);                                              
  Serial.begin(1200);                                             
  pinMode(Motor_CLK, INPUT);                                       
  pinMode(Motor_DT, INPUT);                                         
  attachInterrupt(digitalPinToInterrupt(Motor_CLK), isr, FALLING);
  Serial.begin(2000000);                                                                       
  Serial.println("Start HX711 & Encoder");                                                                 
  scale.begin(DOUT, CLK);
  scale.set_scale(calibration_factor);
  scale.tare();
  Serial.println("Readings:");
  pinMode(in1, OUTPUT);                                                     
  pinMode(IN1, OUTPUT);                                                                            
  pinMode(in2, OUTPUT);                                                                         
  pinMode(IN2, OUTPUT);                                                                            
  pinMode(speed, OUTPUT);                                                                          
  pinMode(buttonPin, INPUT);                                                        
  pinMode(enA, OUTPUT);
}

void loop() 
{   
  while (!Serial.available())
    {
    button.tick(); 
    encoder();  
    hx();                                               
    Menge();
    EndschalterPosition();
    rechtslauf_1_1();
    linkslauf_1_2();
    linkslauf_1_2_zusatz();
    linkslauf_2_1();
    stillstand_1_3_u_2_2();
    rechtslauf_1_4_u_2_3();
    stillstand_1_5_u_2_4();   
    regelung(); 
    }
    empfangen = Serial.read();
    if (empfangen == 1)
    {
     Serial.println("achterl empfangen");
     achterl = 1;
     Sicherheit=0;
    }
    else if (empfangen == 2)
    {
     Serial.println("viertal empfangen");
     viertal = 1;
     Sicherheit=0;
    }
    else
    {
     Serial.println("other data was recived:");
     Serial.print(empfangen);
    }
}






void hx()                                                                  //Waage                                                                                            
{                                                                                                         
  Serial.print("Reading: ");                                                                            
  Serial.print(scale.get_units(), 1);
  Serial.print(" g");
  Serial.println();
}
void encoder()
{     
    if (virtualPosition != lastCount)                                                         
    {                  
    Serial.print(virtualPosition > lastCount ? "Up  :" : "Down:");                            
    Serial.println(virtualPosition);                                    
    lastCount = virtualPosition ;                                                           
    }      
}
void Menge()                          
{ if(Sicherheit==0)                                 
  {
    if(viertal==1)                    
    { Glas_weg=0;      
      Glas_voll=0;
      S=0;
      gewuenschteMenge=250.0;         
    }                                 
    if(achterl==1)                    
    { Glas_weg=0;                     
      S=0;
      Glas_voll=0;
      gewuenschteMenge=125.0;         
    }                                 
  }
}     






                                
void rechtslauf_1_1()
{
  if((Einschenkvorgang == 1)&&(gewuenschteMenge>0.0)&&(bedingung_rechtslauf_1_1==0)&&(Glas_weg==0))         
  {                                                                               
    pwmOutput=180;                                                                  
    analogWrite(enA, pwmOutput);                                                     
    digitalWrite(IN1, LOW);                                                     
    digitalWrite(IN2, HIGH);                                                   
    delay(200);
    pwmOutput=198.75;
    analogWrite(enA, pwmOutput);                                                    
    digitalWrite(IN1, LOW);                                                  
    digitalWrite(IN2, HIGH);                                                  
    delay(200);
    pwmOutput=217.5;
    analogWrite(enA, pwmOutput);                                                   
    digitalWrite(IN1, LOW);                                                    
    digitalWrite(IN2, HIGH);                                                    
    delay(200);
    pwmOutput=255;
    analogWrite(enA, pwmOutput);                                                   
    digitalWrite(IN1, LOW);                                                    
    digitalWrite(IN2, HIGH);                                                  
    bedingung_rechtslauf_1_1 = 1;                                                
  }                                                                         
}
void EndschalterPosition()                                                
{                                                                          
   if(digitalRead(buttonPin)==HIGH)                             
  {                                                                        
    buttonPinWert=1;                                                           
  }                                                                             
}
void linkslauf_1_2()
{
  if((Einschenkvorgang==1)&&(bedingung_rechtslauf_1_1==1)&&(buttonPinWert==1)&&((achterl==1)||(viertal==1))&&(Glas_weg==0))
  {
    Richtung=11;
    scale.tare();
    butState = !butState;
    virtualPosition = 0;
    pwmOutput=255;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, LOW);
    delay(400);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
    Einschenkvorgang++;
    bedingung_linkslauf_1_2_zusatz=1;
    Ablauf=1;
  }
}
void linkslauf_1_2_zusatz()
{
  if((bedingung_linkslauf_1_2_zusatz==1)||(bedingung_linkslauf_2_1_zusatz==1)&&(Glas_weg==0))
  {
    if((virtualPosition > 7000)&&(Richtung==11))
    {
      pwmOutput=180;
    }
    if((virtualPosition < 7000)&&(Richtung==11))
    {
      pwmOutput=255;
    }
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
  }
}
void stillstand_1_3_u_2_2()
{
  if(((scale.get_units())>=6.0)&&((scale.get_units())<gewuenschteMenge-13.5)&&(Einschenkvorgang>=2)&&(Glas_weg==0)&&(Glas_voll==0)&&(S==0))
  {
    pwmOutput=255;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, LOW);
    if(Schluesselfirstsaveposition == 0)
  {
    firstsaveposition=virtualPosition;
  }
    Schluessel2=1;
    Schluessel3=1;
    Schluesselfirstsaveposition=1;
    bedingung_linkslauf_1_2_zusatz=0;
    bedingung_linkslauf_2_1_zusatz=0;
    Sicherheit=1;
    Ablauf=0;
    S=1;
  }
}
void rechtslauf_1_4_u_2_3()
{
  if(((scale.get_units())>gewuenschteMenge-13.5)&&((virtualPosition)>=(lastsavePosition -5000))&&(bedingung_rechtslauf_1_1==1)&&(Schluessel3==1)&&(Glas_weg==0))
  {
    pwmOutput=255;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);
    Schluessel = 1;
    Schluessel3 = 0;
    Ablauf = 0;
    Glas_voll=1;
  }
}
void stillstand_1_5_u_2_4()
{
  if(((virtualPosition)<=(lastsavePosition-5000)&&(Schluessel==1)))
  {
    pwmOutput=0;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, LOW);
    Schluessel=0;      
    Schluessel2=0;
    gewuenschteMenge=0;
    viertal=0;
    achterl=0;
    Schluesselfirstsaveposition=0;
    Ablauf =1;
    Glas_weg=1;
    Einschenkvorgang++;
    Serial.write(5);
  }
}
void linkslauf_2_1()
{
  if((Einschenkvorgang>=3)&&((viertal==1)||(achterl==1))&&(Schluessel==0)&&(Schluessel2==0)&&(Ablauf==1)&&(Glas_weg==0))
  {
    Richtung==11;
    scale.tare();
    pwmOutput=180;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
    delay(200);
    pwmOutput=198.75;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
    delay(200);
    pwmOutput=217.5;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
    delay(200);
    pwmOutput=255;
    analogWrite(enA, pwmOutput);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
    Einschenkvorgang++;
    Ablauf = 0;
    bedingung_linkslauf_2_1_zusatz=1;
  }
}






void regelung()
{ 
  Gewicht=scale.get_units();
  Zeit=millis();
  deltat=Zeit-Zeit2;
  deltag=Gewicht-Gewicht2;
  Zeit2=Zeit;
  Gewicht2=Gewicht;
  Serial.println(deltat);
  Serial.println(deltag);
  Istwert=(deltag*1000)/deltat;
  Sollwert=2.7;
  if((Schluessel2==1)&&(Schluessel3==1)&&(virtualPosition<=firstsaveposition +300)&&(Glas_weg==0)&&(Glas_voll==0))
  {
    if(Istwert<Sollwert)
  {
  S=0;
    do
    { 
      analogWrite(enA, 255);
      digitalWrite(IN1, HIGH);
      digitalWrite(IN2, LOW);
    }
    while(virtualPosition<=lastsavePosition+10);
  }
  }
}
  • Display Programm:
#include <memorysaver.h>
#include <URTouchCD.h>
#include <URTouch.h>
#include <UTFT.h>

UTFT myGLCD(EHOUSE70, 38, 39, 40, 41);
URTouch myTouch(6, 5, 4, 3, 2);


extern uint8_t swiss721_outline[];
extern uint8_t arial_italic[];
extern uint8_t arial_normal[];
extern uint8_t arial_bold[];
extern uint8_t arial_round_16x24[];
extern uint8_t Inconsola[];
extern uint8_t BigFont[];
extern uint8_t DotMatrix_L_Num[];

int currentpage;
int x, y;
int aktion = 0; //zu sendedner Wert für Wahl

void setup()                                        //läuft einmal am anfang
{ 
  Serial1.begin(2000000);
  Serial.begin(9600);
  Serial.println("<Arduino is ready>");  
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_LOW);
  drawHomescreen(); 
  currentpage = 0;
}

void loop()                                        //läuft immer wieder durch
{
  switch (currentpage)
  {
             case 0: 
           
              if (myTouch.dataAvailable()) 
              {
                myTouch.read();
                x=myTouch.getX();
                y=myTouch.getY();
                    if ((x>=1) && (x<=799) && (y>=1) && (y<=479))
                    {
                        myGLCD.setColor(200,0,0);
                        myGLCD.drawRect(1,1,799,479);
                        currentpage = 1; 
                        myGLCD.clrScr(); 
                        drawselectmenu();
                    }
               }
            break;


  
            case 1:
                if (myTouch.dataAvailable()) 
                {
                  myTouch.read();
                  x=myTouch.getX();
                  y=myTouch.getY();
                  
                      if ((x>=130) && (x<=370) && (y>=230) && (y<=420))
                      {   
                          myGLCD.setColor(200,0,0);
                          myGLCD.drawRect(150,250,350,400);
                          delay(20);
                          Serial1.write(1); //schicke achterl an Arduino1
                          Serial.println("1 wurde gesendet");
                          myGLCD.setColor(100,100,100);
                          myGLCD.drawRect(150,250,350,400);
                      }
                      if ((x>=430) && (x<=670) && (y>=230) && (y<=420))
                      {   
                          myGLCD.setColor(200,0,0);
                          myGLCD.drawRect(450,250,650,400);
                          delay(20);
                          Serial1.write(2); //schicke viertal an Arduino1
                          Serial.println("2 wurde gesendet");
                          myGLCD.setColor(100,100,100);
                          myGLCD.drawRect(450,250,650,400);
                      }
                      if ((x>=380) && (x<=420) && (y>=420) && (y<=460))
                      {
                          myGLCD.setColor(200,0,0);
                          myGLCD.drawCircle(400,440,4); 
                          myGLCD.clrScr(); 
                          drawsettings();
                          currentpage = 2;
                      }
                 }              
              break;  


              case 2: 
           
              if (myTouch.dataAvailable()) 
              {
                myTouch.read();
                x=myTouch.getX();
                y=myTouch.getY();
                    if ((x>=400) && (x<=700) && (y>=300) && (y<=400))
                    {
                        myGLCD.setColor(0,0,0);
                        myGLCD.drawRect(450,300,700,400);
                        currentpage = 0;
                        Serial.println("Resetvorgang");
                        Serial1.write(0);
                        aktion = 0;
                        myGLCD.clrScr(); 
                        drawHomescreen();
                        Serial.println("Reset beendet.");
                    }
                    if ((x>=100) && (x<=360) && (y>=300) && (y<=400))
                    {
                        myGLCD.setColor(0,0,0);
                        myGLCD.drawRect(100,300,350,400);              
                        currentpage = 1;
                        Serial.println("SPEZIAL aka Flasche Leer");
                        Serial1.write(3);
                        myGLCD.clrScr(); 
                        drawselectmenu();
                    }
               }
            break;
    
    while (!Serial1.available()){}
    aktion = Serial1.read();
    if (aktion == 5) //Warte auf 5 von Arduino1 (5=fertig)
    {
     Serial.println("Fertig:");
     aktion = 0;
    }
    else
    {
     Serial.println("other data was recived:");
     Serial.print(aktion);
    }

  }

}

void drawHomescreen()
{
  myGLCD.setBackColor(VGA_WHITE); 
  myGLCD.fillScr(255,255,255); 
  myGLCD.setFont(Inconsola);
  myGLCD.setColor(200,0,0);
  myGLCD.print("Welcome",CENTER,200);
  myGLCD.setFont(swiss721_outline);
  myGLCD.print("Touch Anywhere to Start",230,240);
}
void drawselectmenu()
{
  myGLCD.setBackColor(VGA_WHITE);
  myGLCD.fillScr(255,255,255);
  myGLCD.setFont(arial_round_16x24);
  myGLCD.setColor(200,0,0); 
  myGLCD.print("Wieviel darfs denn sein ?",CENTER,100);
  myGLCD.setFont(arial_italic);
  myGLCD.setColor(200,0,0); 
  myGLCD.print("Mengenwahl",CENTER,150);
  myGLCD.setColor(100,100,100); 
  myGLCD.drawRect(150,250,350,400);
  myGLCD.print("Ein Achterl",165,320);
  myGLCD.drawRect(450,250,650,400);
  myGLCD.print("Ein Viertal",465,320);
  myGLCD.drawCircle(400,440,4);
}
void drawsettings()
{
 myGLCD.setBackColor(VGA_WHITE);
 myGLCD.fillScr(255,255,255);
 myGLCD.setFont(Inconsola);
 myGLCD.setColor(0,0,150); 
 myGLCD.print("Settings",CENTER,80);
 myGLCD.drawRect(450,300,700,400);
 myGLCD.setFont(arial_italic);
 myGLCD.print("Reset UI",510,340);
 myGLCD.drawRect(100,300,350,400);
 myGLCD.print("Flasche Leer",130,340);
}

Hallo
Da der Füllvorgang sicher in mehreren Schritten hinter einander ablaufen soll macht es sicher Sinn das in einer Schrittkette zu organisieren.

Such also nach Schrittkette, Ablaufsteuerung, endlicher Automat, in Verbindung mit Arduino. gerne auch hier im Forum. Vorschläge gibt's da reichlich.

Dann must du sicher noch die Anzeige mit in den Sketch Loop einbauen.

Heinz

1 Like

wie würde man das händisch in der Praxis machen?
Das Glas bis zum Ausschenkvorgang hochheben und dann langsam mit der Flaschendrehung mit absenken.
Aus meiner Sicht brauchst du nur mechanisch das Glas mitführen (inkl. deiner Wägeeinheit).
Nicht mal extra ansteuern. passt auch besser zum restlichen netten Aufbau.