DSLR Slider mit Arduino Steuerung

Hallo zusammen

Ich bin noch ein Anfänger in Programmierung und bräuchte etwas Hilfe…Aktuell baue ich mir ein Slider für meine Spiegelreflex. Dieser soll von einer Startposition in eine Endposition fahren und dazwischen Fotos und Pausen machen :smiley:

Am Ende soll er mindesten zwei Achsen haben. Vor und zurück sowie nach links und rechts drehen. Zum Anfang arbeite ich jedoch erst mit einer Achse (vor und zurück).
Als Hardware verwende ich:
• Arduino Uno
• Adafruit LCD RGB Shield
• Stepper Motor
• Den Slider

Den Programmablauf habe ich mir folgendermassen vorgestellt:

  1. Startposition festlegen
    Hier soll der Slider per Knopfdruck nach links oder rechts fahren bis ich mittels Druck auf Select die Startposition festlege.

  2. Endposition festlegen
    Auch hier soll der Slider per Knopfdruck nach links oder rechts fahren bis ich mittels Druck auf Select die Startposition festlege.

  3. Belichtungszeit festlegen
    Hier wird eine Verzögerung festgelegt wie lange der Slider auch dem Auslösen an der Kamera wartet bevor er den nächsten Stepp macht

  4. Los! Aufnahme starten

Wie muss ich ein solches Programm aufbauen?
Meine Überlegung war die Start und End Position als int SetStartPos() zu definieren und aus dem Main Loop zuerst auf SetStartPos verweisen und anschliessend auf SetEndPos. So à la:

#include <Stepper.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

#define RED 0x1
#define YELLOW 0x3
#define GREEN 0x2
#define TEAL 0x6
#define BLUE 0x4
#define VIOLET 0x5
#define WHITE 0x7

int in1Pin = 12;
int in2Pin = 11;
int in3Pin = 10;
int in4Pin = 9;
Stepper motor(512, in1Pin, in2Pin, in3Pin, in4Pin);  


int StartPos;
int curEndPos;
int EndPos = curEndPos;

void setup() {
  // Debugging output
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(3,0);
  lcd.print("Vati's");
  lcd.setCursor(4,2);
  lcd.print("MySlider 2");
}

uint8_t i=0;



//Start Position Festlegen

int SetStartPos() {
  uint8_t buttons = lcd.readButtons();
  motor.setSpeed(20);

  if (buttons) {
    lcd.clear();
    lcd.setCursor(1, 0);
    lcd.print("Set Start Pos");
    if (buttons & BUTTON_UP) {
    lcd.setBacklight(RED);
    }
    if (buttons & BUTTON_DOWN) {
      lcd.setBacklight(YELLOW);
    }
    if (buttons & BUTTON_LEFT) {         
      motor.step(-100);
    }
    if (buttons & BUTTON_RIGHT) {
      motor.step(100);
    }
    if (buttons & BUTTON_SELECT) {
      StartPos = 0;
      lcd.setCursor(6,1);
      lcd.print("OK");
      delay(1000);
      lcd.clear();
    }
}
}

//End Position Festlegen

int SetEndPos() {
  uint8_t buttons = lcd.readButtons();
  motor.setSpeed(20);

  if (buttons) {
    lcd.clear();
    lcd.setCursor(3, 0);
    lcd.print("Set End Pos");
    
    if (buttons & BUTTON_UP) {
      lcd.setBacklight(RED);
    }
    if (buttons & BUTTON_DOWN) {
      lcd.setBacklight(YELLOW);
    }
    if (buttons & BUTTON_LEFT) {
      curEndPos--;           
      motor.step(-100);
      lcd.setCursor(10,1);
      lcd.print(curEndPos);
    }
    if (buttons & BUTTON_RIGHT) {
      curEndPos++;
      motor.step(100);
      lcd.setCursor(10,1);
      lcd.print(curEndPos);
    }
    if (buttons & BUTTON_SELECT) {
      curEndPos = EndPos;
      lcd.setCursor(6,1);
      lcd.print("OK");
      delay(1000);
      lcd.clear();
    }
  }
}


void loop()
{
  lcd.setCursor(1, 0);
  lcd.print("Set Start Pos");
  delay(1000);
  SetStartPos();
  
  lcd.setCursor(2, 0);
  lcd.print("Set End Pos");
  delay(1000);
  SetEndPos();
  
  /*
  
  lcd.setCursor(2, 0);
  lcd.print("Set Blurring");
  delay(1000);
  SetBlurring();  
  
  lcd.setCursor(2, 0);
  lcd.print("Start Timelapse");
  delay(1000);
  Motino Control();
  
  */
}

Allerdings springt das Programm in Einsatz wie wild hin und her…Es wird nicht erst die Start Position festgelegt und weiter gemacht, sondern immer alles durchgespielt. Auch ohne Eingabe.
Ich vermute dass ich irgendwas noch nicht richtig verstanden habe was das aufbauen von solchen Programmen angeht. Vielleicht könnt Ihr mir weiterhelfen..?
Vielen Dank schonmal

Delays von 1s und auf Tastendrücke reagieren funktioniert generell nicht.

Fang vielleicht man eine Stufe kleiner mit einem Taster und einer Funktion an

Hallo Serenifly

Vielen Dank für deine Einschätzung. Was genau meinst du mit "Delays von ls und auf Tastendrücke reagieren funktioniert generell nicht?

Ein Taster und eine Funktion? Also dass ich auf Knopfdruck die Funktion aufrufe?

Ich vermute dass ich irgendwas noch nicht richtig verstanden habe was das aufbauen von solchen Programmen angeht.

Normalerweise soll ein controller nach dem Einschalten ewig laufen.
Dafür gibt es die setup() Funktion, die einmal nach reset durchlaufen wird,
und die loop() Funktion, die immer wieder von neuem gestartet wird.

Optimalerweise wird während eines "Programmablaufs" loop beliebig viele Millionen mal durchlaufen, und jeder loop Durchlauf dauert nur Millisekunden lang oder so. Ausserdem kann man nach einer Aufnahme weiter machen und wahlweise neue Positionen und/oder Belichtungszeiten ändern oder Aufnahmen wiederholen.

Wenn du nur den starren Ablauf wie du ihn beschrieben hast brauchst, vergiss meine ersten Sätze und schreib alles in setup()

Der reset Knopf startet dann dein "Programm" stur von vorn.

Allerdings:

  1. Startposition festlegen
    Hier soll der Slider per Knopfdruck nach links oder rechts fahren bis ich mittels Druck auf Select die Startposition festlege.

Das ist in Wirklichkeit schon recht komplex: Ich nehme an, du hast 3 Knöpfe : Links, Rechts, Select und meist ist kein Knopf gedrückt. Links und Rechts kannst du beliebig lang drücken und loslassen und in beliebiger Reihenfolge, bis der Select-Knopf das Programm 1 beendet und die Startposition für später speichert.

Realisiere erstmal: "Den Motor laufen lassen solange ein Knopf gedrückt ist und ihn stehen lassen wenn der Knopf losgelassen ist"
Dann mit 2 Knöpfen und 2 Richtungen.

Meiner Meinung nach geht das leichter mit der Methode der kurzen schnellen loop Durchläufe.

myown:
Was genau meinst du mit "Delays von ls und auf Tastendrücke reagieren funktioniert generell nicht?

delay() halt den Controller komplett an. Der macht dann einfach eine Schleife in der nichts gemacht wird.
Ereignisse die während dieser Zeit eintreffen existieren für ihn nicht.

Deshalb wie michael_x gesagt hat loop() ständig durchlaufen lassen und die Taster ständig abfragen. Dann was machen wenn etwas gedrückt wurde. Und auch dann auf lange Delays verzichten (oder besser komplett) wenn du während der Aktion auf weitere Tastendrücke reagieren willst.

Zeit-Verzögerungen kann man mit millis() nicht-blockierend machen, in dem man die verstrichene Zeit berechnet.

Ich würde jetzt gerne sagen alles klar :slight_smile: dass wäre aber nicht korrekt ^^
Das mit den Delays habe ich einigermassen verstanden. Ich verwende gerne Serielle Ausgaben (od Display mit delays) um im laufenden Betrieb zu erkennen wo sich das Programm gerade befindet...

Da ich wie erwähnt vermute, dass ich irgendetwas im Grundsatz eines solchen Programms noch nicht verstanden habe, finde ich den Vorschlag von michael_x mich heran zu tasten ganz Sinnvoll.
Ich habe also nochmals einen neuen Sketch verfasst, in welchem ich nur die Knöpfe abfrage und den Motor bei Druck auf rechts oder links bewege:

(Up und DOWN ist später für den zweiten Motor)

#include <Stepper.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

int in1Pin = 12;
int in2Pin = 11;
int in3Pin = 10;
int in4Pin = 9;
Stepper motor(512, in1Pin, in2Pin, in3Pin, in4Pin);  

void setup() {
  lcd.begin(16, 2);
  motor.setSpeed(20);
}

uint8_t i=0;
void loop() {

  uint8_t buttons = lcd.readButtons();

  if (buttons) {
    lcd.clear();
    lcd.setCursor(0,0);
    if (buttons & BUTTON_UP) {
      lcd.print("UP ");
    }
    if (buttons & BUTTON_DOWN) {
      lcd.print("DOWN ");
    }
    if (buttons & BUTTON_LEFT) {
      lcd.print("LEFT ");
      motor.step(-100);
    }
    if (buttons & BUTTON_RIGHT) {
      lcd.print("RIGHT ");
      motor.step(100);
    }
    if (buttons & BUTTON_SELECT) {
      lcd.print("SELECT ");
    }
  }
}

Das funktioniert sehr gut :slight_smile:

Ich möchte nun den Schlitten auf eine beliebige Position stellen, diese als Startposition markieren und dann eine Endposition auswählen...

Ist die Endposition definiert soll der Schlitten auf die Startposition fahren und dann Schritt für Schritt zur Endposition.

Bei der Aufgabenstellung sehe ich schon wieder einen Zustandsautomaten vor meinen Augen :slight_smile:

Das ist in Wirklichkeit schon recht komplex: Ich nehme an, du hast 3 Knöpfe : Links, Rechts, Select und meist ist kein Knopf gedrückt. Links und Rechts kannst du beliebig lang drücken und loslassen und in beliebiger Reihenfolge, bis der Select-Knopf das Programm 1 beendet und die Startposition für später speichert.

Genau so :wink:

Die Startposition wird als Refernz für den Endpunkt gesetzt. Nach Ablauf des Programms muss der Slider nicht zurückfahren. Es soll wieder neuer Start (Refferenzpunkt) und ein neuer Endpunkt gesetzt werden usw...

Wie muss ich dies umsetzen? Ich würde wie im ersten Code Start- und Endposition in eine separate Funktion packen welche die jeweiligen Positionen zurück geben...

So richtig schlau bin ich noch nicht geworden. Ich möchte eigentlich ja nur einen Zahlenwert per Knopfdruck für x festlegen, dann einen für y und mit beiden etwas anstellen...so à la:

definiere x per Knopfdruck, Select
definiere y per Knopfdruck, Select

-> mache x + 1 bis x == Y

Wie kann ich das anstellen?

Generell legt man bei so was erst mal die Nullposition fest. Du willst ja nicht durch beliebige langes Drücken am Anschlag den Motor quälen (oder falls Du das doch willst - dann mach das :smiling_imp: )

Also Enschalter/Gabellichtschranken vorn und hinten.
Beim Starten dann den Nullpunkt anfahren und dann geht's per Handsteuerung los.
Start X hast Du dann praktisch schon durch das Mitzählen der Schritte ab Nullposition.
Select merkt sich die x-Position in entsprechender Variable.
Weiterfahren bis Position y, nächster Select merkt sich y.

Wenn's dann losgehen soll fährst du y-x Schritte zurück und dann im gewünschten Intervall vorwärts mit den üblichen Timings für "Warten bis Stillstand", "Auslösen", "weiterfahren".

Zumindest würde ich das so machen.
Und wo wir gerade dabei sind: mich würde Deine mechanische Konstruktion interessieren. Selbstgebaut, gekauft oder wie sieht das aus? Bild wäre auch nicht schlecht.

Gruß
Klaus

Hallo Klaus

So möchte ich vorgehen...Den Motor könnte ich quälen, will ich aber nicht :smiley: erstmal wollte ich die Programmabfolge hinbekommen.

Aber da happerts noch...

Den Slider habe ich selbst gebaut. Aktuell ist noch alles sehr rustikal, aber ich habe mir nochmal diverse Bauteile bestellt um den Slider auf 1m länge auszubauen. Ich hab ein paar Bilder in den Anhang gepackt :wink:

Das Material ist alles von "MakerBeam". Das Display ist ein Adafruit LCD RGB Shield.

Über Tipps wie ich mein Programm aufbauen muss bin ich dankbar.. :slight_smile:

Grüsse
Andreas

Noch zwei Pics :smiling_imp:

Bist Du jetzt schon weitergekommen oder wie ist der Stand?

Slider sieht sehr stabil aus - was muss man für so was auf den Tisch legen?

Hey,

ich klinke mich da mal mit ein :grin:.

Stabil aussehen tut das wirklich, ich frage mich nur ist das nicht etwas teuer?
Wäre es nicht günstiger gewesen einen Slider mit igus teilen zu machen?

Hier gibt es die Schienen und Schlitten << Hier >>

Zahnriemen udn Zahnriemenscheiben haben die auch gibt es aber auch bei Mädler oder E-Bay

von der Ansteuerung des Motors Endschalter, bleibt alles gleich.

ACHTUNG die Bilder sind nicht meine die habe ich mal herunter geladen aus einem anderen Forum da ich mir so was auch mal bauen wollte.

Gruß Mücke