Schrittmotor über Sharp IR Sensor steuern

Hallo,
Ich bin ein Neuling in der Arduino-Welt und auch ganz allgemein im Programmieren und habe folgende Komponenten:
Arduino Uno R3 SMD Edition, Schrittmotor 28BYJ-48, Sensor: Sharp IR GP2Y0A41SKF (40-300mm)

Das Projekt hat das Ziel den Abstand des Sensors zu verschieden großen Objekten immer beizubehalten. Also der Sensor schaut senkrecht nach unten auf das Objekt und hält über einen Schrittmotor den Abstand von 90mm. Das Objekt wird gewechselt und der Sensor passt den Abstand über den Schrittmotor wieder auf ~ 90mm an. Dieses automatisierte Abstandhalten soll mir bei der Makrofotografie von archäologischen Objekten helfen.

Der bisherige Code:

#include <Stepper.h>
#define STEPS 64
Stepper Schrittmotor(STEPS, 8, 9, 10, 11);
int sensorPin = 0;
int val = 0;
int previous = 0;

void setup()
{
Serial.beginn(9600);
Schrittmotor.setSpeed(100);
}

void loop()
{
val = analogRead(sensorPin);
int valConverted = (207600 / (val-11))/10;
Serial.print("mm")
Serial.println(valConverted);
delay(200);
Schrittmotor.step(valConverted - previous);
}

Was macht der Code:
Er misst ziemlich exakt (zumindest im Bereich um 90mm) den Abstand und zeigt diesen im seriellen Monitor an. Der Motor dreht sich langsam und gleichmäßig im Uhrzeigersinn. Wenn ich jetzt meine Hand in den Sensorbereich halte, bleibt das Drehmoment gleich aber er unterbricht die Bewegung jetzt alle paar Grad. Motor und Sensor interagieren also schon „etwas“.

Meine Frage ist: wie muss ich den Code umschreiben, dass der Motor folgende Bewegungen ausführt?

Objekt im Bereich =90mm: Motor stop,
Objekt im Bereich > 90mm: Motor dreht sich Clockwise,
Objekt im Bereich < 90mm: Motor dreht sich Counterclockwise.

Vielen Dank
Jan

Montiere einen PIR Bewegungssensor so daß er Deine Hand erkennt und steuere so den Motor-Stop Der Pir erkennt Deine Hand aber nicht das Objekt (da ja kalt).

Grüße Uwe

Hallo Uwe,

vielen Dank für die Antwort. Das Beispiel mit der Hand war im ersten Post mißverständlich ausgedrückt. Ich nutze halt nur meine Hand um die Messwerte und die Reaktion des Motors zu prüfen. Nein es geht um ein Objekt. Ich möchte zwar eine Abstandsreaktion haben, aber eine Distanzabhängige.

Viele Grüße,
Jan

Hallo Jan,
ich habe Deinen Aufbau nicht, darum ist es etwas schwierig, das nachzubauen. Ich arbeite daher mit Textausgaben, um den Ablauf deutlich zu machen:

#include <Stepper.h>
#define STEPS 64
Stepper Schrittmotor(STEPS, 8, 9, 10, 11);
int sensorPin = A0;
int val = 0;
int sollAbstand = 90;
unsigned long aktMillis;
unsigned long prevMillis;
const unsigned int intervall = 1000;

void setup() {
  Serial.begin(9600);
  Serial.println("Programmanfang");
  Schrittmotor.setSpeed(100);
}

void loop() {
  if (millis() - prevMillis >= intervall) {
    prevMillis = millis();
    val = analogRead(sensorPin);
    Serial.print("Messwert: "); Serial.print(val); Serial.print("    ");
    int valConverted = (207600 / (val - 11)) / 10;
    Serial.print("abs. Abstand: "); Serial.print(valConverted); Serial.print(" mm     ");
    Serial.print("rel. Abstand: "); Serial.print(valConverted - sollAbstand); Serial.println(" mm");
    //  Schrittmotor.step(schritte);
  }
}

Ausgabe:
Messwert: 241 abs. Abstand: 90 mm rel. Abstand: 0 mm

Wenn Du den relativen Abstand in Schritte für Schrittmotor.step() umrechnest, dabei das richtige Vorzeichen erwischst, sollte der Motor in die richtige Richtung drehen.

Werte von val kleiner 12 solltest Du abfangen, somst saust der Motor unkontrolliert los.

Dann habe ich Dich falsch verstanden.
Grüeß Uwe

Hallo agmue,

vielen Dank für Deine Hilfe. Das sieht sehr schön im seriellen Monitor aus. Und die Umrechnung als rel. Abstand ist auch eine Hilfe. Der Motor dreht sich nicht, aber es gibt ja auch keinen Befehl dazu.

Das versuche ich dann mal.

Bsp: der "rel Abstand" ist 21mm....Meine Gewindestange, an welcher der Schlitten mit Kamera und Abstandssensor befestigt wird, hat eine Steigung von 1,25mm pro Umdrehung. So brauche ich 16,8 Umdrehungen um 21mm zu überwinden.
Die Umdrehung multipliziere ich mit der Anzahl der STEPS die der Motor für eine Umdrehung braucht und habe damit die gesamte Anzahl der Steps. In diesem Falle also 16,8 * 64 = ~1075 Steps

Der Sketch sieht jetzt folgendermaßen aus:

#include <Stepper.h>
#define STEPS 64
Stepper Schrittmotor(STEPS, 8, 9, 10, 11);
int sensorPin = A0;
int val = 0;
int sollAbstand = 90;
unsigned long aktMillis;
unsigned long prevMillis;
const unsigned int intervall = 1000;

void setup() {
  Serial.begin(9600);
  Serial.println("Programmanfang");
  Schrittmotor.setSpeed(100);
}

void loop() {
  if (millis() - prevMillis >= intervall) {
    prevMillis = millis();
    val = analogRead(sensorPin);
    Serial.print("Messwert: "); Serial.print(val); Serial.print("    ");
    int valConverted = (207600 / (val - 11)) / 10;
    Serial.print("abs. Abstand: "); Serial.print(valConverted); Serial.print(" mm     ");
    Serial.print("rel. Abstand: "); Serial.print(valConverted - sollAbstand); Serial.println(" mm");

    float relAbstand = (valConverted - sollAbstand);
    float Steigung = 1.25
    Schrittmotor.step((relAbstand / Steigung)*STEPS);
    delay(50);

  }
}

Es passiert aber leider nichts. Der Motor dreht sich gleichmäßig im Uhrzeigersinn. Er reagiert auch nicht mehr auf eine Hand oder einen Gegenstand. Im seriellen Monitor werden die Messwerte jetzt nur noch alle halbe Minute aufgezeichnet und nicht im Sekundentakt wie bei Deinem Sketch. Was hab ich falsch gemacht?

Viele Grüße
Jan

Kleine Erweiterung:

 float relAbstand = (valConverted - sollAbstand);
    float Steigung = 1.25;
    int Schritte = (relAbstand / Steigung)*STEPS;
    Serial.print("Schritte: "); Serial.print(Schritte); Serial.print("   ");
    Schrittmotor.step(Schritte);
    Serial.println("fertig");

Anzeige: Messwert: 197 abs. Abstand: 111 mm rel. Abstand: 21 mm Schritte: 1075 fertig

Schrittmotor.step() ist blockierend, wartet also, bis die Bewegung beendet ist. Der Schrittmotor sollte sich also 1075 Schritte drehen, bis "fertig" kommt. Danach sollte der Meßwert dann "0" sein.

Die Verzögerung von einer Sekunde greift nicht, wenn die Bewegung länger dauert. War aber auch nur für die Lesbarkeit der Anzeige gedacht.

Da ich gerade einen L298N als Treiber probiere, habe ich mal einen Schrittmotor angeschlossen. Bei STEPS 96 und der Anzeige Messwert: 238 abs. Abstand: 91 mm rel. Abstand: 1 mm Schritte: 76 fertig dreht der Motor ca. eine dreiviertel Umdrehung.

Bei der Anzeige Messwert: 240 abs. Abstand: 90 mm rel. Abstand: 0 mm Schritte: 0 fertig bleibt der Motor stehen.

Sieht für mich gut aus.

Hallo Agmue,

vielen Dank für Deine Antwort. Ich kann den Sketch gut nachvollziehen, glaube aber langsam, dass der Motor samt Treiber problematisch sind. Bei mir dreht sich der Motor kontinuierlich weiter.
Ich werde mal einen Nema17 ausprobieren. Muß aber erst der GY-4988 Treiber gelötet werden. Mache ich dann morgen.

Moment....ich habe mal die Kabel vom Treiber zum Arduino ausgetauscht, nach dem ich das hier gelesen hatte [#6]:

http://forum.arduino.cc/index.php?topic=143276.0

von:

1 auf 8--> 8
2 auf 9--> 10
3 auf 10--> 9
4 auf 11-->11

jetzt funktionierts...Toll :slight_smile:

Objekt im Bereich =90mm: Motor stop,
Objekt im Bereich > 90mm: Motor dreht sich Clockwise,
Objekt im Bereich < 90mm: Motor dreht sich Counterclockwise.

Vielen Dank und viele Grüße
Jan

Glückwunsch! -> Freuen :slight_smile:

Es gäbe noch Optimierungsmöglichkeiten, über die nachzudenken lohnen könnte. So wäre beispielsweise die Umrechnung Spannung (0-1023) -> Abstand (mm) -> Schritte hinsichtlich Genauigkeit zu überprüfen. Auch wäre ein Verfahrweg möglicherweise besser in mehreren Schritten durchzuführen. Oder Automatik aus, manuelles Verfahren.

Ich bin wirklich froh und danke Agmue, dass der Motor nun das macht was ich will.

Aber es stimmt auch, dass die Ansteuerung des Motors etwas unflexibel ist.
Der Sensor misst einen Wert; dieser wird mit dem Sollwert verglichen und daraufhin eine Aktion ausgeführt. Und so muß man, wie "Agmue" schreibt, nach dem blockierenden Befehl "Schrittmotor.step()" warten, bis diese Schritte umgesetzt sind, bevor ein neuer Messwert ausgewertet werden kann.

Besser wäre vielleicht eine Umsetzung in kurzen Intervallen.
Also nehmen wir an, ein Abstand von 110mm wird gemessen. Der Motor setzt sich in Bewegung um die Distanz wieder auf 90mm zu veringern. Alle (z.B.) 50ms wird der Abstand überprüft, die Bewegungsrichtung neu ausgerechnet und sofort umgesetzt. Dann wäre nicht mehr die Anzahl der Steps relevant, sondern die Bewegungsrichtung.

Das wäre nützlich, wenn ich eine Fotoserie von der Oberfläche meines archäologischen Objektes machen möchte. Ich könnte das Objekt langsam unter meiner Kamera durchschieben, diese macht Intervallaufnahmen und wird kontinuierlich auf 90mm Abstand gehalten.

Ich werde mal versuchen was in der Richtung zu machen.

Hallo,

#include <Stepper.h>
#define STEPS 64
Stepper Schrittmotor(STEPS, 8, 9, 10, 11);
int sensorPin = A0;
int val = 0;
int sollAbstand = 90;
unsigned long aktMillis;
unsigned long prevMillis;
const unsigned int intervall = 1000;

void setup() {
  Serial.begin(9600);
  Serial.println("Programmanfang");
  Schrittmotor.setSpeed(100);
}

void loop() {
  if (millis() - prevMillis >= intervall) {
    prevMillis = millis();
    val = analogRead(sensorPin);
    Serial.print("Messwert: "); Serial.print(val); Serial.print("    ");
    int valConverted = (207600 / (val - 11)) / 10;
    Serial.print("abs. Abstand: "); Serial.print(valConverted); Serial.print(" mm     ");
    Serial.print("rel. Abstand: "); Serial.print(valConverted - sollAbstand); Serial.println(" mm");
    
    if (valConverted >= 90)
    {Schrittmotor.step(-51);}

    if (valConveted == 90)
    {Schrittmotor.step(0);}

    if (valConverted <= 90)
    {Schrittmotor.step(51);}
      
  }
}

ich habe für diesen Versuch die Zeilen entfernt, die sich mit der Umrechnung und Darstellung der STEPS im seriellen Monitor beschäftigt haben. Außerdem noch den Befehl "Schrittmotor.step(Schritte);"

Um mich vorsichtig aber kontinuierlich dem Objekt anzunähern bzw den Abstand zu halten (der Abstand darf nicht größer werden als mein Schärfentiefebereich von +-5mm), schien mir 1 mm Hub pro Messintervall angemessen.
Das heißt bei einer Spindel mit einer Steigung von 1,25 mm pro Umdrehung und 64 Steps (die der Motor braucht für eine Umdrehung) sind das 51,2 Steps für einen Millimeter Hub.
Sagen wir 51 Steps.
Jetzt bewegt der Motor die Kamera immer um 1 mm pro Messung auf das Objekt zu, bzw. vom Objekt weg.

Leider kontrolliere ich den Sketch immer noch nur mit meinem Billigmotor 28bYJ-48. Und der reagiert so was von langsam. Es funktionier so schon ganz gut (immer noch lahm), aber ich hoffe das wird mit dem Nema17 besser.

Am besten wäre eine Lösung ohne "Schrittmotor.step()". Dafür ein Messintervall im Mikrosekundenbereich und eine ständige Reaktion des Motors darauf.

Hat da jemand eine Idee? :o

Viele Grüße
Jan

MakroPix:
Alle (z.B.) 50ms wird der Abstand überprüft, die Bewegungsrichtung neu ausgerechnet und sofort umgesetzt.

MakroPix:
Um mich vorsichtig aber kontinuierlich dem Objekt anzunähern bzw den Abstand zu halten (der Abstand darf nicht größer werden als mein Schärfentiefebereich von +-5mm), schien mir 1 mm Hub pro Messintervall angemessen.

Die zweite Idee gefällt mir deutlich besser!

MakroPix:
... 64 Steps (die der Motor braucht für eine Umdrehung) ...
... mit meinem Billigmotor 28bYJ-48 ...

Mein Schrittmotor sieht genauso aus, braucht 64 Schritte pro Motorumdrehung und beinhaltet ein Getriebe 1:64, also 64 * 64 = 4096 Schritte pro Umdrehung der Welle! Oder? Da es sich nach meinem Verständnis um einen unipolaren Motor handelt, kann der überhaupt von Stepper.h angesteuert werden? Also lahm weil falsch angesteuert?

MakroPix:
Hat da jemand eine Idee?

Diesen Motor, der ja eine Verstärkerschaltung mitgeliefert bekommt, habe ich ohne Bibliothek direkt angesteuert. Kohlekran. Der Schwerpunkt ist der endliche Automat, die Funktion schrittMotor() kannst Du aber sicherlich verwenden. Es ist eine Beschleunigungs- und Bremsrampe eingebaut, die sich auch akustisch gut macht.

Ich hoffe, die Ideen gefallen.