Sauguino, die vollautomatische Plattenwaschmaschine...

Zwischen den Jahren hatte ich endlich mal ein bisschen Zeit und hab mich an ein lange wartendes Bastelprojekt gemacht... eine Plattenwaschmaschine. Die Threads hier zu den Bastelprojekten haben mich ungemein inspiriert, allein ich wollte es so komfortabel wie nur irgend möglich, denn mir verging bei den manuellen Methoden meist nach drei oder vier Platten die Lust am Waschen.

Hier kann man sich die Maschine in Action ansehen.

Als Basis diente ein alter Dual 1226, den ich extra dafür angeschafft hatte (5,- EUR in der Amateurbucht). Sein Reibradantrieb hat mächtig Drehmoment. :slight_smile: Ansonsten gab's als Anschaffung nur noch die Pollin-Vakuumpumpe (9,95) und einen Arduino Micro für die Steuerung (20,-). Nahezu alle anderen Teile flogen in Bastelkisten rum oder kosteten nur Cents (wie die mir ausgegangenen 2k2 Widerstände...)

Mein Ziel war es, den Plattenwaschprozess so weit wie möglich zu automatisieren, damit man nicht ständig daneben sitzen muss. Dazu brauchts folgende Aktoren:

  • Natürlich den Plattenspielermotor zum Drehen
  • Elektromagnet, um die Bürste (ich nehm dieses Clearaudio Samt-Teil) hochzuklappen
  • Vakuupumpe für Punktabsaugung
  • Elektromagnet, um den Tonarm anheben zu können (ungedämpft reicht...)
  • Servo, um den Tonarm einigermaßen genau steuern zu können

Dazu hab ich den Dual erstmal kräftig zerlegt -- leider hatte ich während der Bastelei keine Lust auf Fotos.
Auf diesem Nachher-Bild kann man die Umbauten aber ganz gut erkennen:

1: Als erstes habe ich Platinenfedern rausgerissen. Eine PWM muss schliesslich nicht entkoppelt sein. Das Chassis liegt jetzt einfach auf einem Streifen Tesa Moll, so läuft auch kein Wasser unten ins Gehäuse.

2: Die Hebel und Teile für Antiskating, Lift und Start/Stop habe ich alle entfernt. Den Tonarm steuere ich jetzt selber, den Plattentellermotor ebenso. Ausserdem lieferte das mir einige praktische Teile, die ich zweckentfremden konnte :slight_smile:
Der 33/45-Wähler ist geblieben. Schadet nicht. Im Moment wasche ich mit 45 upm.

3: Diese Wippe wird an sich durch die Steuerscheibe (gelb) bewegt und gedrückt und bewegt dadurch den Tonarm. Da ich die Steuerscheibe nicht ausgebaut bekommen habe, habe ich den Wippendrehpunkt ein Stück nach aussen versetzt, das Ding ein bisschen zurecht gehobelt und einen kleinen Elektromagnet (5) drunter geklebt. Zieht der an, hebt sich der Tonarm. Das Silikonöl musste ich allerdings fluten, damit dessen Kraft reicht. Der Magnet stammt aus irgendeinem alten Kassettenrekorder...

4: Der Dremel und die Trennscheibe haben Platz für einen Mini-Servo geschnitten, der jetzt oben unterm Tonarm rausguckt (s.u.). Ein Stück vom alten Automatikgestänge war nahezu perfekt geformt, um den Tonarm mittels Servo über die ganze Platte hin und her zu bewegen. Die Wippe (3) musste ich ein bisschen zurecht sägen, damit sie nicht mit dem Steuerarm ins Gehege kommt. Beachtlich, wie viel Kraft so ein Servo hat und wie oft er einem die schönsten Basteleien flugs wieder zerlegt...

6: Hier drin sitzt der Schalter für den Motor. Ich hab mich einfach auf dessen Kontakte gelötet, das Kabel zugentlastet durchgeführt und die Kappe wieder drauf geschraubt. Das Schalten übernimmt jetzt ein Relais -- das einzige mit 230V drauf.

7: Der silberne Hebel wird an sich von der Steuerscheibe bewegt und tut Zweierlei: Reibrad an den Teller legen und den Motor an- und ausschalten. Ich hab die kleine Feder einfach so umgehängt, dass das Reibrad jetzt immer anliegt.

Der keine Billigservo, der den Tonarm hin und her bewegt. Genutzt werden ca. 160° seines Weges.

Der Bürstenhalter war etwas Frickelei in Buche. Nut gefräst für die Clearaudio-Bürste, mittig aufgehängt, um gleichmässigen Andruck zu gewährleisten. Der E-Magnet (auch Pollin) hat mächtig Wumms. An sich zieht er auch noch gegen eine straffe Feder an, mit der hätte die Bürste dann ordentlichen Andruck auf der Platte gehabt. Zum einen war das aber zu viel, zum anderen zieht er unter Last mehr als 3A bei 12V und das schafft mein Netzteil nicht auf Dauer. Daher habe ich die Feder entfernt und sorge für den Andruck mit ein paar Pfundmünzen. :slight_smile: Wenn er einmal angezogen hat, ist die Bürste durch eine gewisse Verkantung stabil hochgeklappt. Schiebt man die Scheibe mit dem Griff hoch, liegt die Bürste wieder auf. Nachdem ich das Holz schön gewachst habe, quillt es auch nicht mehr auf und sorgt für Verkantungen...

Die Absaugdüse hat sich auch mit der Zeit ergeben -- funktioniert jetzt aber so gut, dass ich sie so lasse. Basis ist ein Chupachup-Lollystil (leicht angekaut). Unten dran ist ein Stück ganz weicher Silikonschlauch, der perfekt über die Platte rutscht, auch wenn gut dran gesaugt wird. Zusammen mit der Reinigungsflüssigkeit flutscht das so glatt, dass ich mir den üblichen Faden gespart habe. Löcher und Führung für einen Faden sind vorhanden, das Trockenergebnis ist aber ohne Faden viel besser und ich ziehe keinen Schmodder im Faden durch die frisch gereinigten Rillen. War mir so sympathischer.

Rechts die Bedieneinheit... 4 Taster durch ein Stück Sperrholz gesteckt. Die Plastikwanne des Dual ist über 1 cm dick, da bekam ich keine Schalter drin montiert. Das Sperrholzbrettchen ist einfach mit schwarzem Tesaband überzogen (Lack trocknet immer so lange). Die 7-Segment-Anzeige für die gewünschte Waschdauer ist so hell, dass die magisch durch das Tesaband durchscheint. Sieht ungewollt ziemlich cool aus und man sieht meine Sägekunst nicht so. :slight_smile:

Nochmal das Bedien-Panel:

Blick in die Zarge. Mit etwas Trickserei habe ich alles in der Zarge direkt unterbringen können, nur das Abscheiderglas nicht. Aber das will man ja auch sehen. :slight_smile: Praktisch ist, dass die PWM so echt kompakt geworden ist und prima auf dem Geraffelschrank stehen kann. Links hinten die Pollin-Saugpumpe. (Wenn man beide Ventile anzieht, saugt sie auch. Doh.) Rechts vorne sieht man den Rand eines alten Notebook-Netzteils... 12V und ca. 3.5A -- bis auf den Plattentellermotor wird damit alles angetrieben und versorgt. Rechts auf der Lochrasterplatine die Intelligenz des ganzen:

Links in blau der Arduino Micro. Er steuert vor allem die vier Relais (jeweils über einen BC548 und Freilaufdiode), zum anderen aber auch das 7-Segment-Display. Dessen "Treiber" ist links oben ein CMOS 4511, das für BCD-Codes die richtigen LEDs ansteuert. Hätte der Arduino auch direkt gekonnt, aber so spart man ein paar Leitungen und ich hatte noch ein 4511. :slight_smile: Eingangsseitig sind nur die 4 Taster angeschlossen. Ach ja, und den Servo steuert er auch direkt an.

So sieht der Sauguino komplett aus. Die Saugdüse habe ich abgenommen, damit der Schlauch nicht verknickt. Im Regal kommt das Joghurtglas natürlich noch ab. Den zentralen An/Ausschalter muss man etwas suchen, aber nur hier war die Zarge dünn genug. :slight_smile:

Der Code dazu, etwas Spaghetti-esque:

// PWauf Basis eine Dual 1226
// 24.12.2012 Friedemann Wachsmuth

#include <Servo.h> 

Servo tonarmservo; 

// TODO:
//
// Gewicht fehlt

// Ausgänge
int PumpenPin = 4;
int LiftPin = 11;
int TellerPin = 2;
int BrushPin = 3;
int BlankPin = 12; // PWM
int ServoPin = 9; // PWM
int Apin = 18;
int Bpin = 19;
int Cpin = 20;
int Dpin = 21;
int DPpin = 22;

// Eingänge
int IncSwPin = 5;
int DecSwPin = 6;
int StartstopSwPin = 7;
int SettingSwPin = 8;

// Frei: 10,13, 23

byte IncSwState = 1;
byte DecSwState = 1;
byte StartstopSwState = 1;
byte SettingSwState = 1;

// Konfiguration
float homePos = 75;
float startPos = 102;
float endPos = 165;
float suckSpeed = 1500;
int actionDelay = 1000;
byte washMinutesDesired = 3;

#define IDLE  1
#define WASH  2
#define SUCK  3
#define FINISH 4
#define WASHINIT 5
#define WASHEND 6
#define STOP 7
#define SETTINGS 8
#define WAITASEC 9
#define INITSETTINGS 10

int pos = 0;    // variable to store the servo position 0
byte mode = IDLE;
unsigned long washbegin;
byte washMinutesRemaining;
byte washMinutesDisplayed;
unsigned long washMillisRemaining;
unsigned long settingsPushBegin;
byte oldStartPos;

void setup() 
{ 
  analogWrite(ServoPin, homePos);  

  pinMode(Apin, OUTPUT);     
  pinMode(Bpin, OUTPUT);     
  pinMode(Cpin, OUTPUT);     
  pinMode(Dpin, OUTPUT);     
  pinMode(DPpin, OUTPUT);     
  pinMode(BlankPin, OUTPUT);     
  pinMode(PumpenPin, OUTPUT);     
  pinMode(LiftPin, OUTPUT);     
  pinMode(TellerPin, OUTPUT);    
  pinMode(BrushPin, OUTPUT); 
  pinMode(Dpin, OUTPUT);     

  tonarmservo.attach(ServoPin);  // attaches the servo to the servo object 

  pinMode(IncSwPin, INPUT); 
  digitalWrite(IncSwPin, HIGH);  
  pinMode(DecSwPin, INPUT);     
  digitalWrite(DecSwPin, HIGH);
  pinMode(StartstopSwPin, INPUT);     
  digitalWrite(StartstopSwPin, HIGH);
  pinMode(SettingSwPin, INPUT);     
  digitalWrite(SettingSwPin, HIGH);

  tonarmservo.write(homePos);
  // Serial.begin(9600);
  digitalWrite(BlankPin, HIGH);

  seg7(washMinutesDesired);

} 

void loop() 
{ 
// Serial.println(mode);
// delay(2);

  checkButtons();

  switch(mode) {
    case IDLE:
      updateTimer();
      if  (StartstopSwState == LOW) {
        mode = WASHINIT;
        delay(300);
      } else if (SettingSwState == LOW) {
        settingsPushBegin = millis();
        mode = WAITASEC;
        delay(300);
      }
      break;
    case WASHINIT:
      washinit();
      break;
    case WASH:
      wash();
      break;
    case WASHEND:
      washend();
      break;
    case SUCK:
      suck();
      break;
    case WAITASEC:
      waitasec();
      break;
    case INITSETTINGS:
      init_settings();
      break;
    case SETTINGS:
      settings();
      break;
    case STOP:
      stop();
      break;
  }
}

void updateTimer() {
  if  (IncSwState == LOW) {
    washMinutesDesired = min(8, washMinutesDesired)+1;
    washMinutesDisplayed = washMinutesDesired;
    seg7(washMinutesDisplayed);
    delay(300); // Debounce
  }
  if  (DecSwState == LOW) {
    washMinutesDesired = max(2, washMinutesDesired)-1;
    washMinutesDisplayed = washMinutesDesired;
    seg7(washMinutesDisplayed);
    delay(300); // Debounce
  }
}  
  
void washinit() {
  digitalWrite(TellerPin, HIGH);
  delay(actionDelay * 2);
  // Hier Bürste absenken
  washbegin = millis();
  mode = WASH;
}  

void wash() {
  updateTimer();
  if  (StartstopSwState == LOW) {
    mode = WASHEND;
    delay(300); // debounce
  }
  washMillisRemaining = (((washMinutesDesired*60000)-(millis()-washbegin)));
  washMinutesRemaining = washMillisRemaining / 60000;
  if ((washMillisRemaining / 500) % 2 == 1) {
    digitalWrite(DPpin, LOW); // halbsekündig blinken: Countdown läuft!
  } else {
    digitalWrite(DPpin, HIGH);
  }
  if (washMinutesRemaining+1 < washMinutesDisplayed) {
    seg7(washMinutesRemaining+1);
    washMinutesDisplayed = washMinutesRemaining + 1;
  }
  if (washMillisRemaining/1000 == 0) {
    mode = WASHEND;
  }
  
}

void washend() {
  digitalWrite(DPpin, LOW);
  delay(actionDelay);
  digitalWrite(BrushPin, HIGH); // Bürste wegfluppen
  delay(100); // Der Magnet zieht knapp 3A...
  digitalWrite(BrushPin, LOW);
  delay(actionDelay); // Abtropfen lassen

  mode = SUCK;
}
 
void suck() {
  seg7(0);
  digitalWrite(DPpin, LOW);

  digitalWrite(TellerPin, HIGH);
  digitalWrite(LiftPin, HIGH);
  delay(actionDelay);
  tonarmservo.write(endPos);
  digitalWrite(PumpenPin, HIGH);
  delay(actionDelay);
  digitalWrite(LiftPin, LOW);
  delay(actionDelay);
  
  for(pos = endPos; pos>=startPos; pos-=1) {
    tonarmservo.write(pos);
    // Serial.println(suckSpeed * (1+(endPos - pos) / 60));
    // delay(1);
    delay(suckSpeed * (1+(endPos - pos) / 60)); // Sugdauer aussen gegenüber innen verdoppeln
    // Auf Abbruch checken...
    SettingSwState = digitalRead(SettingSwPin);
    if (SettingSwState == LOW) {
      mode = STOP; 
      break;
    }
  }
  mode = STOP;

}  

void stop() {
  digitalWrite(TellerPin, LOW);
  digitalWrite(LiftPin, HIGH);
  delay(actionDelay);
  tonarmservo.write(homePos);
  delay(actionDelay);
  digitalWrite(PumpenPin, LOW);
  delay(actionDelay);
  digitalWrite(LiftPin, LOW);
  delay(actionDelay);

  seg7(washMinutesDesired);
  washMinutesDisplayed = washMinutesDesired;

  mode = IDLE; 
}

void checkButtons() {
  IncSwState = digitalRead(IncSwPin);
  DecSwState = digitalRead(DecSwPin);
  StartstopSwState = digitalRead(StartstopSwPin);
  SettingSwState = digitalRead(SettingSwPin);  
}

void waitasec() {
  if (SettingSwState == LOW) {
    if (millis() > (settingsPushBegin + 2000)) {
      mode = INITSETTINGS;
    } 
  } else {
    mode = IDLE;
    delay(300);
  }
}

void settings() {
  Serial.println(startPos);
  delay(1);
  tonarmservo.write(startPos);
  if (IncSwState == LOW) {
    startPos = min(endPos,startPos--);
    delay(100);
  } else if (DecSwState == LOW) {
    startPos = max(homePos,startPos++);
    delay(100);
  } else if (StartstopSwState == LOW) {
    delay(100);
    tonarmservo.write(endPos);
    delay(200);
    tonarmservo.write(startPos);
    delay(200);
    tonarmservo.write(endPos);
    delay(200);
    tonarmservo.write(startPos);
    delay(200);
    stop();
    mode = IDLE;
  } else if (SettingSwState == LOW) {
    delay(100);
    tonarmservo.write(oldStartPos);
    delay(400);
    startPos = oldStartPos;
    stop();
    mode = IDLE;
  }
}

void init_settings() {
  digitalWrite(LiftPin, HIGH);
  delay(actionDelay);
  tonarmservo.write(startPos);
  oldStartPos = startPos;
  mode = SETTINGS;
}


void seg7(byte number) {
  digitalWrite(Dpin, ((number >> 3) & 1) ? HIGH : LOW);
  digitalWrite(Cpin, ((number >> 2) & 1) ? HIGH : LOW);
  digitalWrite(Bpin, ((number >> 1) & 1) ? HIGH : LOW);
  digitalWrite(Apin, (number & 1) ? HIGH : LOW);
}