Go Down

Topic: Steuerung eines Kamerasliders (Read 5916 times) previous topic - next topic

agmue

#45
May 10, 2016, 07:55 pm Last Edit: May 10, 2016, 07:57 pm by agmue
Oder es läuft wieder auf einen Zustandsautomaten hinaus. Läuft auch permanent durch. Dafür liefert dir sicherlich agmue seine Bsp. und Link.
Das hatte ich schon mal gemacht, fand aber nicht so den Anklang (Stand 24.4.2016):
Code: [Select]
#include <AccelStepper.h>

#define TASTERpin  2
#define STEPpin  8
#define DIRpin   9
#define AusloeserPin 13
AccelStepper Xaxis(1, STEPpin, DIRpin);
const unsigned long ruhe = 1000, aufnahme = 100, pause = 500;
unsigned long aktMillis, fotoMillis;
long pos;
enum {WARTEN, BEWEGUNG, BERUHIGUNG, AUFNAHME, PAUSE};
const byte maxZ = 5;
byte zaehler, zustand = WARTEN;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(TASTERpin, INPUT_PULLUP);
  pinMode(AusloeserPin, OUTPUT);
  Xaxis.setMaxSpeed(500);
  Xaxis.setAcceleration(500);
}

void loop() {
  aktMillis = millis();
  switch (zustand) {
    case WARTEN:
      if (digitalRead(TASTERpin)) {
        pos = analogRead(A0);
        Serial.print("pos: ");
        Serial.println(pos);
        Xaxis.move(pos);
        zustand = BEWEGUNG;
      }
      break;
    case BEWEGUNG:
      if (Xaxis.distanceToGo() == 0) {
        fotoMillis = aktMillis;
        zustand = BERUHIGUNG;
      }
      break;
    case BERUHIGUNG:
      if (aktMillis - fotoMillis >= ruhe) {
        digitalWrite(AusloeserPin, HIGH);
        fotoMillis = aktMillis;
        zustand = AUFNAHME;
      }
      break;
    case AUFNAHME:
      if (aktMillis - fotoMillis >= aufnahme) {
        digitalWrite(AusloeserPin, LOW);
        fotoMillis = aktMillis;
        zustand = PAUSE;
      }
      break;
    case PAUSE:
      if (aktMillis - fotoMillis >= pause) {
        zaehler++;
        zaehler = zaehler % maxZ;
        if (!zaehler) {
          Serial.println("Fertig, warten auf neuen Zyklus.");
          zustand = WARTEN;
        } else {
          Xaxis.move(pos);
          zustand = BEWEGUNG;
        }
      }
      break;
  }
  Xaxis.run();
}
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Doc_Arduino

Hallo,

für die Steuerung brauchst du Variablen für die Zustände. Sprich, du baust dir einen Zustandsautomaten. ;)
Der Code von agmue sieht doch gut aus. Haste dir den wenigstens mal angesehen? Wäre Schade drum wenn nicht.
In Ruhe durch ackern bist du weist was er macht. Ausdrucken, Notizen reinmalen etc. ...

Bei Deinem Encoder müßte man erstmal schauen was er für Signale liefert um damit sinnvoll arbeiten zu können.
Hast du überhaupt einen Encoder dran? Wenn ich den Thread überblicke hast du doch gar keinen?

Wünsche erstmal angenehmen Urlaub.
 
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Fototobi94

#47
May 11, 2016, 09:23 am Last Edit: May 11, 2016, 09:32 am by Fototobi94
Das Beispiel von Agmue habe ich mir schon öfter angeguckt, zum großen Teil auch verstanden. Switch war für mich komplett neu. Das Ganze Zeug um millis() muss ich noch verstehen. Mir ist auch nicht klar, warum sich der Motor bewegt, wenn die zurückzulegende Distanz = 0 ist??
Code: [Select]
if (Xaxis.distanceToGo() == 0)

Ich kann das doch durch
Code: [Select]

stepper.move(Position*microstep); //Schritte, die gefahren werden berechnen
stepper.runToPosition(); //Schritte fahren

ersetzen.

Ich mag es aber auch nicht, einfach einen fertigen Sketch zu übernehmen für meine Steuerung. Der Encoder ist ein standard Drehencoder mit 12 Rastungen pro Umdrehung und einem eingebauten Taster.

Ein paar Stichworte, über die ich mich in den nächsten 2 Wochen erstmal Informieren sollte:

- millis() und 'BlinkWithoutDelay'
- Zustandsautomat
- Encoder richtig verwenden
- Interrupts am Arduino <- Gerade gesehen, dann sollte der Encoder funktionieren

Fällt euch noch was ein, worüber ich mich informieren sollte?

Wünsche erstmal angenehmen Urlaub.
Vielen Dank!  :smiley-sweat:

Doc_Arduino

Hallo,

es ist keine Schande fremden Code zu verwenden, noch dazu wenn man ihn frei angeboten bekommt. Sonst dürfte man auch keine fremden Libs benutzen. Hauptsache ist immer das man ihn versteht und nicht blind übernimmt. Dann ist doch schon viel gewonnen. Bei umfangreichen Libs ist das schwierig, ist mir bewußt. Du wirst in Zukunft eh noch viel selbst schreiben.

Wegen dem Schrittmotor Problem. Da kann ich dir leider nicht weiterhelfen. Habe z.Z. keinen Stepper hier und auch keine passende Ansteuerung. Mein Gefühl sagt mir jedoch, dass du zu schnell weiter springst mit der Stepper-Lib. Die Doku von dem ist doch eigentlich gut gemacht.

wenn hier was anderes geliefert wird wie Null, wird der Fehler vermutlich woanders liegen.
Code: [Select]
if (Xaxis.distanceToGo() == 0)


Zwischenergebnisse mittels Serial.print ist Debugging des kleinen Mannes.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

agmue

#49
May 11, 2016, 09:28 pm Last Edit: May 12, 2016, 10:45 am by agmue
Kurz aus dem Urlaub:
Code: [Select]
Xaxis.move(pos);
"Renne zu dieser Position relativ zur alten, aber warte nicht auf das Erreichen der Position!"

Code: [Select]
if (Xaxis.distanceToGo() == 0)
"Warte, bis die durch move vorgegebene Position erreicht ist."

Wird es damit klarer?

Ich wünsche Dir einen erholsamen Urlaub und ein Arduino gehört mit ins Reisegepäck  :smiley-cool:

PS.: Ich habe ja Leuten beim Nutzen eines Sliders zugeschaut. Die haben zigmal die Position ausprobiert, bevor es für das Model "Action" hieß. Daher solltest Du auch einen Einstellmodus haben, bei dem die einzelnen Positionen für eine beliebeige Zeit angefahren bleiben. Allerdings haben die Leute ein Video gedreht, Du machst ja wohl Fotos.

In meinem Sketch müßte im Ablauf WARTEN noch erweitert werden auf das Einstellen der variablen Werte.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Fototobi94

Ich bin wieder da. Ich hätte nicht gedacht, dass es im Schwarzwald so viele Funklöcher gibt, dann auch noch in der Ferienwohnung  :smiley-confuse:

PS.: Ich habe ja Leuten beim Nutzen eines Sliders zugeschaut. Die haben zigmal die Position ausprobiert, bevor es für das Model "Action" hieß. Daher solltest Du auch einen Einstellmodus haben, bei dem die einzelnen Positionen für eine beliebeige Zeit angefahren bleiben. Allerdings haben die Leute ein Video gedreht, Du machst ja wohl Fotos.
Das Ganze spare ich mir, da ich die Kamera vor der Montage auf dem Schlitten auch kurz von Hand von A nach B bewegen kann.

Ich bin immer noch hin und her gerissen, ob ich jetzt deinen Sketch übernehme oder meinen eigenen schreibe. Ich hänge momentan bei folgendem Problem fest:

Der Encoder soll im loop ja laufend ausgelesen werden, aber der Arduino zählt die Variable nur etwa alle 4-9 Drehimpulse um 1 hoch. Liegt das daran, dass der Sketch ja weiterläuft und nur in dem Moment zählt, in dem er an dieser Stelle ist? Ich glaube für den Encoder müsste ich Interrupts verwenden, aber ich habe nur 2. Einen Interrupt-Pin wollte ich für die Endtaster frei halten, da der Schlitten dort auf jeden Fall sofort anhalten muss.

Im Beispiel 'Encoder Basic' steht, dass der Encoder mit einem oder 2 Interrupts betrieben werden kann, wie müsste ich das dann mit einem Interrupt anstellen?

Mein Versuch sieht so aus, jedoch erhalte ich eine Fehlermeldung:

Code: [Select]
#include <AccelStepper.h>
#include <Encoder.h>

#define stepPin 5 //deklariert StepPin des DRV8825
#define dirPin  4 //deklariert dirPin  des DRV8825
#define EncoderPinA 3 //deklariert Encoder Pin A
#define EncoderPinB 2 //deklariert Encoder Pin B

int microstep = 8; //DRV8825 im 1/8-Schritt Modus

// Definiert Stepper und die benutzten Pins
AccelStepper stepper(1, stepPin, dirPin); //erstellt Accelstepper-Objekt mit namen 'stepper'

// Definiert Encoder und die benutzten Pins
Encoder myEnc(2, 9);

void setup(){
  attachInterrupt(0, encoderLesen, CHANGE);
  stepper.setMaxSpeed(800*microstep); //maximale geschwindigkeit
  stepper.setAcceleration(300*microstep); //Beschleunigung
  Serial.begin(9600);
}

long newPosition;

void loop(){   
  stepper.move(newPosition*microstep); //Schritte, die gefahren werden berechnen
  stepper.runToPosition(); //Schritte fahren
  Serial.println(newPosition);
}

long oldPosition = -999;

void encoderLesen(){
     newPosition = (myEnc.read()/4);
     if (newPosition != oldPosition) {
     oldPosition = newPosition;
     Serial.println(newPosition);
     }
    return newPosition;
}


Fehlermeldung ist: return-statement with a value, in function returning 'void' [-fpermissive]

'Void' gibt ja keinen Wert zurück, deshalb habe ich 'void encoderLesen' durch 'long encoderLesen' ersetzt. Jetzt kommt:
invalid conversion from 'long int (*)()' to 'void (*)()' [-fpermissive]

Wie gebe ich den Wert in die Hauptfunktion zurück? In deinem Sketch würde es besser funktionieren, Agmue, oder?


Nochmal kurz zu den Endtastern: Ich möchte jetzt Mikroschalter mit einem kleinen Metallhebel benutzen. Beim Schalten sollen dann der Interrupt-Pin zum Anhalten und ein Weiterer Pin für die Richtungserkennung (Endschalter links oder rechts) benutzt werden. Dafür geht auch ein Analoger Pin.

agmue

Es könnte daran liegen: "ISRs are special kinds of functions that have some unique limitations most other functions do not have. An ISR cannot have any parameters, and they shouldn't return anything."
In deinem Sketch würde es besser funktionieren, Agmue, oder?
Nein, da ich den Encoder überhaupt nicht berücksichtigt habe. Ich habe keinen Encoder und damit auch keinerlei praktische Erfahrung damit.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Fototobi94

Ich habe es jetzt mal mit deinem Code probiert. Mit dem Encoder lässt sich jetzt ein Wert vorwählen, den Zähler habe ich entfernt. Wenn ich auf den integrierten Button drücke, fängt der Stepper an zu laufen. Nur stoppen kann ich ihn nicht, Werte lassen sich nach dem Starten auch nicht mehr ändern.

Ich möchte dort noch einen Start/Stoptaster einbauen, die Lib kenne ich schon. Nur wohin gehört er? Baue ich in der Switch/Case Funktion noch einen Case ein? Oder frage ich den Taster außerhalb der Funktion ab?

Code: [Select]
#include <AccelStepper.h>
#include <Encoder.h>


#define EncoderButton  6
#define STEPpin  5
#define DIRpin   4
#define AusloeserPin 13
AccelStepper Xaxis(1, STEPpin, DIRpin);
const unsigned long ruhe = 1000, aufnahme = 100, pause = 500;
unsigned long aktMillis, fotoMillis;
long pos;
enum {WARTEN, BEWEGUNG, BERUHIGUNG, AUFNAHME, PAUSE};
const byte maxZ = 5;
byte zustand = WARTEN;

Encoder myEnc(8, 9);

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(EncoderButton, INPUT_PULLUP);
  pinMode(AusloeserPin, OUTPUT);
  Xaxis.setMaxSpeed(1000);
  Xaxis.setAcceleration(1000);
}

long oldPosition  = -999;

void loop() {
   long newPosition = myEnc.read();
  if (newPosition != oldPosition) {
    oldPosition = newPosition;
    Serial.println(newPosition);
  }

  
  aktMillis = millis();
  switch (zustand) {
    case WARTEN:
      if (digitalRead(EncoderButton)) {
        pos = newPosition;
        Serial.print("pos: ");
        Serial.println(pos);
        Xaxis.move(pos);
        zustand = BEWEGUNG;
      }
      break;
    case BEWEGUNG:
      if (Xaxis.distanceToGo() == 0) {
        fotoMillis = aktMillis;
        zustand = BERUHIGUNG;
      }
      break;
    case BERUHIGUNG:
      if (aktMillis - fotoMillis >= ruhe) {
        digitalWrite(AusloeserPin, HIGH);
        fotoMillis = aktMillis;
        zustand = AUFNAHME;
      }
      break;
    case AUFNAHME:
      if (aktMillis - fotoMillis >= aufnahme) {
        digitalWrite(AusloeserPin, LOW);
        fotoMillis = aktMillis;
        zustand = PAUSE;
      }
      break;
    case PAUSE:
      if (aktMillis - fotoMillis >= pause){
        Xaxis.stop();
        zustand = WARTEN;
        } else {
          Xaxis.move(pos);
          zustand = BEWEGUNG;
        }
      break;
      }
  Xaxis.run();
}

DrDiettrich

Ich frage mich, was die Zeitsteuerung im Zustand PAUSE soll. Sollte da nicht eher abgefragt werden, ob eine neue Position angefahren werden soll? Dazu sollte beim Einlesen vom Encoder die alte Position nicht überschrieben werden, damit nachher ein Vergleich erfolgen kann. Erst bei Erreichen der neuen Position wird diese zur oldPosition, für den nächsten Vergleich.

Go Up