Position eines Schrittmotors speichern

Hallo Leute!

Ich habe eben mit Arduino Uno und dem Adafruit Motor Shield V2 begonnen (C-Kenntnisse vorhanden) und stehe vor einem kleinen Problem. Ich habe mir eine Metallbox gebaut auf der sich eine Metallscheibe mit Hilfe eines Schrittmotors drehen soll.
Hier mal ein Screenshot der Konstruktion:

Der Schrittmotor wird so angesteuert, dass immer das nächste Loch in der Scheibe an der roten Markierung stehen bleibt. Wenn man während des Betriebs allerdings den Netzstecker zieht und so der Motor stehen bleibt, so würde sich beim nächsten Neustart der Motor ja um die vorgegebene Anzahl an steps weiterdrehen und die Löcher würden nicht mehr mit der Markierung übereinstimmen... Jetzt wäre natürlich die Möglichkeit, einen Endlagenschalter oder eine Lichtschranke zu verwenden, ich dachte aber eher an eine Lösung mittels Board und Code (EEPROM eventuell).

Wäre nett wenn mir da jemand einen Denkanstoß geben würde.

LG Patrick

Ich glaube, ohne eine andere Prüfungsmöglichkeit wirst Du nicht kinkommen.

Drei Szenarien, die zum Misserfolg führen:

a) Du speicherst vor Beginn der Schritte die Position, der Stom ist weg bevor der Motor die Sollposition erreicht hat

b) Du willst nach Erreichen der Sollposition speichern aber der Strom ist vorm Speichern weg

c) Du speicherst vor und nach der Bewegung. 2 gleiche Werte = ok. Wenn es nur der 1. Wert ist, weißt Du nicht, wo der Motor steht.

Gruß Tommy

Kann die Scheibe mit der Hand verdreht werden?

Danke für die raschen Antworten.

Die Scheibe lässt sich händisch bewegen. Habe eben in einem Video eines ähnlichen Gerätes eine Lösung gefunden. Es wird mit Hilfe von Markierungen auf dem Gerät und der Scheibe vor dem Start die Scheibe händisch justiert. Für mein Vorhaben absolut ausreichend. Somit wäre meine Frage eigentlich erledigt.

LG Patrick

Wenn die Scheibe manuell gedreht werden kann ist eine Speicherung der nicht sinnvoll, weil die Position falsch sein kann. Du kannst einen Sensor verbauen der eine bestimmte Position der Scheibe detektiert und somit die Position der Scheibe bekannt ist. Wahrscheinlich muß beim Einschalten des Gerätes die Scheibe eine volle Umdrehung machen um die Nullsellung zu finden.

Grüße Uwe

Wäre jemand bitte so nett und würde über mein Sketch drübersehen?

Folgendes soll erreicht werden:

Hardware:
Schrittmotor 1 - 200 Steps, 6rpm
Schrittmotor 2 - 513 Steps, 60rpm
Poti: min 0, max 1023
Taster - Ein-/Aus
Arduino Uno
Adafruit Motor Shield V2.3

Taster "true": bei erstmaligem Betätigen -> 4 Sekunden warten
Analogen Wert des Poti's auslesen (min und Max soll auf 15 Werte aufgeteilt werden)
Wert vergleichen

Abhängig vom Ergebnis soll sich Motor 1 immer 20 Steps bewegen und Motor 2 n-Sekunden lang drehen (513 Steps = eine Umdrehung; bei 60rpm dauert eine Umdrehung eine Sekunde)

Das ganze Spielchen soll solange wiederholt werden bis der Taster erneut gedrückt wird.

Hier mal der Code, erstellt mit meinen bescheidenen und ewig nicht mehr angewendeten C-Kenntnissen:

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); 

// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *bigMotor = AFMS.getStepper(200, 2);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #1 (M1 and M2)
Adafruit_StepperMotor *smallMotor = AFMS.getStepper(513,1);

const int minPoti = 0;
const int maxPoti = 1023;
int einAusPin = 2;
int potiPin = 0;


void setup() {
  //Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(einAusPin, INPUT);            // PIN 2 = INPUT (Haupttaster)
  
  //Serial.println("CASE ANNEALER!");

  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
  
  bigMotor->setSpeed(6);    // 6 rpm  
  smallMotor->setSpeed(60);  // 60 rpm   
}

void loop() {
  
  int einAusTaster;
  int i=0;
  int wertPoti;
  int sekunden;

  einAusTaster = digitalRead(einAusPin);
  
  while (einAusTaster){

    if (i == 0){
      delay(4000);      // 4 Sekunden bis die Rotation beginnt
    }
    else{
      i++;  
      wertPoti = analogRead(potiPin);
      sekunden = map(wertPoti, minPoti, maxPoti, 0, 14);
      switch(sekunden){
        case 0:
          Serial.println("0 Sekunden");
          break;
        case 1:
          Serial.println("1 Sekunde");
          bigMotor->step(20, FORWARD, SINGLE);    // Hauptmotor dreht bis zur nächsten Hülse 
          smallMotor->step(513*sekunden, FORWARD, SINGLE);  // Drehteller dreht sich
          break;
        case 2:
          Serial.println("2 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break
        case 3:
          Serial.println("3 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 4:
          Serial.println("4 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 5:
          Serial.println("5 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 6:
          Serial.println("6 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 7:
          Serial.println("7 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 8:
          Serial.println("8 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 9:
          Serial.println("9 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 10:
          Serial.println("10 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 11:
          Serial.println("11 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 12:
          Serial.println("12 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 13:
          Serial.println("13 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
        case 14:
          Serial.println("14 Sekunden");
          bigMotor->step(20, FORWARD, SINGLE);
          smallMotor->step(513*sekunden, FORWARD, SINGLE);
          break;
      }
      delay(1);   // Pause für Stabilität zwischen dem Einlesen
    }
  }
}

Ich hoffe ich habe mein Vorhaben halbwegs erklären können.

patrickk83:
Das ganze Spielchen soll solange wiederholt werden bis der Taster erneut gedrückt wird.

Das funktioniert nicht, da Du while (einAusTaster){} nie verläßt.

     switch(sekunden){}

ginge einfacher (ungetestet):

     sekunden = map(wertPoti, minPoti, maxPoti, 0, 14);
          Serial.print(sekunden);
          Serial.println(" Sekunde(n)");
      if(sekunden){
          bigMotor->step(20, FORWARD, SINGLE);    // Hauptmotor dreht bis zur nächsten Hülse
          smallMotor->step(513*sekunden, FORWARD, SINGLE);  // Drehteller dreht sich
          }

Ein Taster hat nur zwei Zustände, daher

bool einAusTaster;

Der Sinn von i erschließt sich mir nicht.

Ob es für den Bediener praktisch ist, ein Poti als Stufenschalter nutzen zu müssen, bezweifle ich.

Einmal den Taster gedrückt und die automatische Bewegung kann wegen delay(4000) nicht gestoppt werden. So eine Maschine dürfte mehreren Vorschriften widersprechen.

patrickk83:
Wäre jemand bitte so nett und würde über mein Sketch drübersehen?

Habe ich, wolltest Du so :slight_smile:

Hallo und danke für's Überprüfen.

Der Taster ist eigentlich ein Schalter, habe ich vergessen zu erwähnen.

Das switch werde ich dann mal nach deinem Vorschlag abändern.

Zur Variable i: Ich müsste erkennen, ob das Gerät gerade eingeschaltet wurde. Es soll dann eben diese 4 Sekunden verweilen und dann mit der eigentlichen Funktion starten. Ich denke aber, ich kann dies ohnehin vernachlässigen. Wofür ist das Serial.print(sekunden); eingebaut? Die Ausgabe über Serial habe ich vorerst nur zum Testen eingebaut, die kommt dann wieder weg.

Wäre es so funktionaler?

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); 

// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *bigMotor = AFMS.getStepper(200, 2);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #1 (M1 and M2)
Adafruit_StepperMotor *smallMotor = AFMS.getStepper(513,1);

const int minPoti = 0;
const int maxPoti = 1023;
int einAusPin = 2;
int potiPin = 0;


void setup() {
  //Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(einAusPin, INPUT);            // PIN 2 = INPUT (Haupttaster)
  
  //Serial.println("CASE ANNEALER!");

  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
  
  bigMotor->setSpeed(6);    // 6 rpm  
  smallMotor->setSpeed(60);  // 60 rpm   
}

void loop() {
  
  int einAusSchalter;
  int i=0;
  int wertPoti;
  int sekunden;

  einAusSchalter = digitalRead(einAusPin);
  
  while (einAusSchalter){

    if (i == 0){
      delay(4000);      // 4 Sekunden bis die Rotation beginnt
    }
    else{
      i++;  
      wertPoti = analogRead(potiPin);
      sekunden = map(wertPoti, minPoti, maxPoti, 0, 14);

      if(sekunden){
        bigMotor->step(20, FORWARD, SINGLE);    // Hauptmotor dreht bis zur nächsten Hülse 
        smallMotor->step(513*sekunden, FORWARD, SINGLE);  // Drehteller dreht sich
      }
      delay(1);   // Pause für Stabilität zwischen dem Einlesen 
    }
  }
}

LG

patrickk83:
Wäre es so funktionaler?

Bezogen auf switch ja.

Und der Rest?

Nö, while wird immer noch nicht verlassen :o

Hab ich jetzt verstanden :slight_smile:

So müsste es jetzt aber funktionieren oder?

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); 

// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *bigMotor = AFMS.getStepper(200, 2);
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #1 (M1 and M2)
Adafruit_StepperMotor *smallMotor = AFMS.getStepper(513,1);

const int minPoti = 0;
const int maxPoti = 1023;
int einAusPin = 2;
int potiPin = 0;
int i = 0;


void setup() {
  //Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(einAusPin, INPUT);            // PIN 2 = INPUT (Haupttaster)
  
  //Serial.println("CASE ANNEALER!");

  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
  
  bigMotor->setSpeed(6);    // 6 rpm  
  smallMotor->setSpeed(60);  // 60 rpm   
}

void loop() {
  
  int einAusSchalter;
  int wertPoti;
  int sekunden;

  einAusSchalter = digitalRead(einAusPin);
  
  if (einAusSchalter == HIGH){

    if (i == 0){
      delay(4000);      // 4 Sekunden bis die Rotation beginnt
    }
    else{
      i++;  
      wertPoti = analogRead(potiPin);
      sekunden = map(wertPoti, minPoti, maxPoti, 0, 14);

      if(sekunden){
        bigMotor->step(20, FORWARD, SINGLE);    // Hauptmotor dreht bis zur nächsten Hülse 
        smallMotor->step(513*sekunden, FORWARD, SINGLE);  // Drehteller dreht sich
      }
      delay(1);   // Pause für Stabilität zwischen dem Einlesen 
    }
  }
  else{
    //Nichts
  }
}

Danke und LG

Ohne while ist loop die Schleife, so soll es sein :slight_smile:

patrickk83:
Zur Variable i: Ich müsste erkennen, ob das Gerät gerade eingeschaltet wurde. Es soll dann eben diese 4 Sekunden verweilen und dann mit der eigentlichen Funktion starten. Ich denke aber, ich kann dies ohnehin vernachlässigen.

Das funktioniert nach Reset und bei Überlauf der Variablen. Das ergibt keinen Sinn, zumindest nicht für mich.

:slight_smile: Na es wird ja schön langsam...

Ich benötige noch eine Lösung um nur nach dem ersten Betätigen des Ein-/Aus-Schalters eine Wartezeit von 4 Sekunden zu erreichen. Hättest du da einen Vorschlag für mich?

Eine globale Variable boot auf true setzen und nach dem ersten Schalten und der Pause auf false.

Gruß Tommy

Dankeschön!

Sowas möglicherweise:

bool verzoegerung = true;

void loop() {

  bool einAusSchalter;
  int wertPoti;
  int sekunden;

  einAusSchalter = digitalRead(einAusPin);

  if (einAusSchalter == HIGH) {

    if (verzoegerung) {
      delay(4000);      // 4 Sekunden bis die Rotation beginnt
      verzoegerung = false; // hier richtig
    }
    else {
      // verzoegerung = false; // hier falsch
      wertPoti = analogRead(potiPin);
      sekunden = map(wertPoti, minPoti, maxPoti, 0, 14);

      if (sekunden) {
        bigMotor->step(20, FORWARD, SINGLE);    // Hauptmotor dreht bis zur nächsten Hülse
        smallMotor->step(513 * sekunden, FORWARD, SINGLE); // Drehteller dreht sich
      }
      delay(1);   // Pause für Stabilität zwischen dem Einlesen
    }
  }
  else {
    verzoegerung = true;
  }
}

EDIT 18.10.2017: Sketch korrigiert

Müsste das "verzoegerung = false;" nicht innerhalb der if-Schleife nach dem delay(4000); stehen?

if ist keine Schleife (if wiederholt nichts) sondern eine Abfrage.
Ansonsten hast Du recht.

Gruß Tommy

Sorry, wieder mal beim Tippen nicht richtig mitgedacht. Natürlich ist if keine Schleife :slight_smile:

Super, dann sollte meinem Projekt ja nichts mehr im Weg stehen.

Danke für die Hilfe, Problem gelöst.

LG