Motor Position regeln

Moin,

ich möchte mein erstes Projekt mit einem DC Motor und einer Positionsregelung machen.

Motortreiber, Motor und Positionsmessung habe ich schon.
Den Motor kann ich vorwärts und rückwärts fahren lassen.
Der Motortreiber ist ein TB9051FTG.
Angesteuert wird der durch PWM.

Nun ist die Frage: Wie realisiere ich die Positionregelung?

Projektdetails: Im Prinzip ist das ein Linearantrieb, der vorgegebene Positionen anfahren und halten soll. Also quasi ein Linearservo. Eine Referenzfahrt kann ich nicht machen. Daher brauche ich einen Absolutwertgeber.

Ein Getriebemotor treibt über eine Gewindemutter einen Hubkolben an. Mit einem TOF Sensor wird gemessen wo der Hubkolben steht. Steht der Hubkolben nicht da wo er sein soll fährt der Motor dort hin.
Gerne mit Beschleunigungs- und Abbremsrampe und auch etwas Totband.

Noch habe ich kein Sketch. Ich brauche erstmal eine konkrete Richtung, in die ich loslaufen kann.
Ich wollte jetzt nicht selber einen PID Regler programmieren. Das gibt es ja sicherlich schon fertig.

Können das die MoBaTools?
Oder wie/wo fängt man damit an?

Besten Dank und viele Grüße,
Chris

Ein PID Regler ist einfacher programmiert als andere Regler gleicher Leistungsfähigkeit. Problematisch ist die Parametrierung, wie auch bei jedem anderen Regler.

Für Rampensteuerung könnte die AccelStepper Bibliothek als Muster dienen. Doch dann kann eine bestimmte Geschwindigkeit oder Beschleunigung nur für Schrittmotoren einfach vorgegeben werden, weil sonstige Motoren keinen festen Zusammenhang zwischen Strom bzw. Spanung und Geschwindigkeit aufweisen, dabei spielt mindestens die Belastung, Reibung etc. noch eine Rolle.

Hallo,
Du schreibst das ein Fenster grundsätzlich möglich ist. Im einfachtsen Fall baust Du eine schnell-langsam-stopp Steuerung auf. Dazu nutzt man 2 Fenster und Geschwindigkeiten von 1:10 wenn es genauer sein soll. 1:3 geht aber auch schon oft.

Ich würde zunächst die Richtung bestimmen Differenz= Soll-Ist positv rechts negativ links. Dann bildest Du den Absolutwert der Differenz. Ist diese grösser als Fenster2 dann Motor schnell. Ist sie grösser als Fenster1 dann langsam. ansonsten stop. ist also ziemlich einfach if...else if.. else.
Kann man alles schön in eine Funktion packen. Die Parameter legst Du in einer Struct ab. Oder wenn Du das mehrfach benötigst baust Du gleich eine Classe.
Heinz

Verstehe.
Allerdings ist das noch nicht die Lösung, die ich suche.

Im Prinzip ist das ja eine einfache Servosteuerung.
Ich bin ja nicht der erste, der eine Servosteuerung bauen will.
Daher vermute ich, dass es Libraries gibt mit denen man das mit weniger Aufwand machen kann.
Sowas suche ich.

Beste Grüße,
Chris

Ich habe Schwierigkeiten das zu glauben!

Ein Tipp für die Zukunft, bei ähnlichen Problemen:
Google: "Arduino PID Library"

Wo?

Liegt aktuell im Keller...:grin:
...die Hardware

Ja, ich dachte da mehr an die Info WAS das für ne Hardware ist. Also Link, Bild, oder so. Denn wir sehen nicht in deinen Keller.

Ich habe mich mal für jemand anders mit dem VL53L0X Time-of-Flight beschäftigt. Welche Genauigkeit erwartest du von dem TOF-Sensor? Und wie schnell soll sich der Kolben bewegen den du kontrollieren willst?

VL53L0X ist korrekt.
Geschwindigkeit ca. 3-4mm pro Sekunde
Genauigkeit 1mm
Totband 1mm

Das wären so die Wunschdaten.
Ob das funktioniert muss natürlich getestet werden.
Dafür baue ich gerade den Testaufbau....

Ja, das sagt die Werbung. Und stimmte auch oft. Und das war immer eine feststehende Entfernung. Wenn sich das Teil auf den Sensor zubewegt, oder vom Sensor weg. Da glaube ich das nicht. Aber ja, dann mußt du mal testen, wenn du auf eine bestimmte Entferung testest, und dann stoppst, wo du dann wirklich landest und wie genau das Ergebnis reproduzierbar ist. Ich bin gespannt, was da rauskommt. Also ich würde da lieber mit nem Schrittmotor arbeiten, da kann ich den Weg auf weit unter nem mm bestimmen. Und wiederholbar, so oft man will.

Das mit dem Schrittmotor ist richtig, aber das passt nicht zu meiner Anwendung.
Ich muss absolut messen. Ich kann und will keine Referenzfahrt machen.
Es kommt auch nicht auf einen Millimeter drauf an.
Zur Not reichen auch 5mm.
Muss ich testen...

So heute konnte ich erstmalig mal schauen was der Sensor so zu Tage fördert.

Nach ein paar tausend Messungen mit verschiedenen Einstellungen kristallisieren sich folgende Werte heraus:
kleinster je gemessener Abstand 79,0mm
größter je gemessener Abstand: 152,3mm
größte Differenz zwischen allen Messwerten bei mechanisch unverändertem Abstand 2,7mm

Daraus leite ich mir folgende Werte ab, die die Grenzen darstellen sollen:
Kleinste Position: 85mm
Größte Position 150mm
Wiederholgenauigkeit/Totband: 3mm

....nun weiss ich allerdings nicht wie ich jetzt mit der Positionsregelung anfangen soll?!

Motor fahrenlassen, gleichzeitig TOF werte auswerten, entspricht der Wer der gewünschter Position Motor ausschalten. Weis nicht in welcher Form die TOF daten liegen vor.

Momentan sieht es so aus:

#include <TB9051FTGMotorCarrier.h>
#include <vl53l0xTOFA.h>
#include <Wire.h>
VL53L0xTOFA sensor;
float smoothLength = 0;
float signalrate = 0;
float ambientrate = 0;
const int analogInPin = A0;  // Analog input pin that the potentiometer is attached to
int sensorValue = 0;        // value read from the potentiometer
// TB9051FTGMotorCarrier pin definitions
static constexpr uint8_t pwm1Pin{12};
static constexpr uint8_t pwm2Pin{14};
//static constexpr uint8_t ocmPin{A1};
// Instantiate TB9051FTGMotorCarrier
static TB9051FTGMotorCarrier driver{pwm1Pin, pwm2Pin};
//static TB9051FTGMotorCarrier driver{pwm1Pin, pwm2Pin, ocmPin};
static float throttlePercent{0.00f};

float runningAverage(int M) {
#define LM_SIZE 10
  static int LM[LM_SIZE];      // LastMeasurements
  static byte index = 0;
  static float sum = 0;
  static byte count = 0;
  sum -= LM[index];         // keep sum updated to improve speed.
  LM[index] = M;
  sum += LM[index];
  index++;
  index = index % LM_SIZE;
  if (count < LM_SIZE) count++;
  return sum / count;
}

void setup() {
  Serial.begin(9600);
  Wire.begin();
  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1) {}
  }
  driver.enable();
  driver.setOutput(throttlePercent);
  sensor.startContinuous();
}

void loop() {
  sensorValue = analogRead(analogInPin);
  //Serial.print("sensor = ");
  //Serial.print(sensorValue);
  //Serial.print(" ");
  if (sensorValue > 565) {
    throttlePercent = map(sensorValue, 565, 1024, 40, 100) / 100.00;
  } else {
    if (sensorValue < 425) {
      throttlePercent = map(sensorValue, 425, 0, -40, -101) / 100.00;
    } else {
      throttlePercent = 0;
    };
  };
  driver.setOutput(throttlePercent);
  //Serial.print(throttlePercent);
  //Serial.print(" ");
  smoothLength = runningAverage(sensor.readRangeContinuousMillimeters());
  sensor.readTOFA();
  smoothLength = runningAverage(sensor.tofa.distancemm);
  signalrate = sensor.tofa.signalrate;
  ambientrate = sensor.tofa.ambientrate;
  Serial.print(smoothLength);
  if (sensor.timeoutOccurred()) {
    Serial.print(" TIMEOUT");
  }
  Serial.println();
}

Ich kann den Motor mit einem Joystick vorwärts und rückwärts fahren lassen und der Sensor misst die Entfernung.

Der Motor wird mit +1.00 (vorwärts) bis -1.00 (rückwärts) in 1% Schritten angesteuert.
Der Abstandssensor stellt Werte von 85 bis 150 (Millimeter) raus. Das Totband soll 3 (Millimeter) betragen.

Ja, so kenne ich das auch. Bei mir war der Messbereich in dem es funktionierte immer so 40-250mm. Und soweit ich mich erinnere, bis 3mm Fehler. Abgesehen von den wenigen totalen Ausreißern.

Im Bereich 300mm war es bedenklich, also unbrauchbar. Aber um diese Bereiche ist es auch nicht gegangen.

Hallo,
unter#3 habe ich Dir einen Vorschlag gemacht, den wolltest Du nicht.

Wenn Du eine Regelkreis aufbauen willst dann schau Dir die PID-Regler Lib und die Beispiele dazu an. Allerdings wenn Du eine "Lose" in Deinem System hast wird das mit einem geschlossenen Regelkreis schwierig. Eventuell musst Du die Position immer von einer Seite anfahren, zudem wird Dir der Motor bei einer "Lose" eventuell ständig auf der Sollposition "rumbrummeln" schwingen . Vermutlich ist das der Grund warum Du ein Fenster von 425-565 in der Mittelstellung des Potis hast.
Damit musst Du eventuell den Motor abschalten, das bedeutet das du den Regelkreis "auf" machst und Dir somit der I-Anteil vom PID wegdriften kann. Wenn Du dann wieder zuschaltest gibts einen "Ruck". Maßnahme : I Anteil abschalten und auf "0" festhalten. Wenn Du zusätzlich noch Rampen für den Antrieb verwenden willst musst Du Dir überlegen ob Du die auf der Sollwertseite des PID Reglers verwendest oder bei der Stellgrösse für den Motor. Letzteres hat dann wieder einen Einfluss auf die Regelparameter.

Ich bin immer noch der Meinung der Vorschlag aus #3 ist ein guter Anfang. Auch das "Anfahren von immer der gleichen Seite", ist kein wirkliches Problem. Wenn Du zudem bereits wegen der Lose über ein "Totband" nachdenkst, bietet sich das sowieso an. Zudem kann ich mir nicht vorstellen das sich bei abgeschaltetem Motor die Position verändern kann. Damit macht ein "auf Position" halten keinen Sinn.

Warum willst Du das überhaupt so machen ? Es gibt fertige Linearmotore mit absolut Istwert Geber.

Heinz

#3 entspricht nicht meiner Vorstellung.
Ich möchte nicht in zwei Stufen den Motor schalten, sondern mit einer stufenlosen Rampe aus einer Position in die nächste weich reinschwenken. Warum? Sagen wir, weil es mir ergonomischer, ästhetischer, was auch immer erscheint. Es sagt mir mehr zu.

Ich habe zwar noch keinen Positionsregler gebaut, und daher selber keine praktische Erfahrung damit gemacht? Aber das Verhalten, dass du Beschreibst hast du bei einem scharf eingestelltem Regler ohne Totband. Der versucht jede kleinste Abweichung sofort mit Vollgas auszuregeln.

Bei mir ist das ja genau das andere Ende der Fahnenstange.

Weil ich ein relativ großes Totband habe fährt der Regler da weich rein und bleibt stehen. Fertig. Mehr wird nicht nachgeregelt.

Das Fenster von 425-565 hat damit nichts zu tun. Das ist das Totband vom Joystick. Wenn ich aus der einen Richtung komme bleibt es bei 425 stehen und aus der anderen Richtung bei 565. Es stellt also nicht sauber in die Mittelstellung zurück (liegt wohl an der Gummifeder...spielt aber keine Rolle, weil es aktuell nur zum manuellen spielen verbaut ist, später kommt es raus und wird digital angesteuert)

Eine Rückstellkraft gibt es nicht, die die Position von aussen verändert. Ausserdem ist der Antrieb selbstsperrend.

Das 3mm Totband ergibt sich aus der Istwerterfassung. Der VL53L0X kann es nicht genauer.

Mein Linearantrieb ist ein 75mm Hohlzylinder, der von einer aussenliegenden Spindelmutter angetrieben wird. Die Spindelmutter wird von einem umschlungenen Zahnriemen mit DC Getriebemotor angetrieben. Hub etwa 65-70mm. Die gesamte Mimik dient dazu einen Elektromotor in der Höhe zu verstellen. Der Elektromotor treibt ein Rasenmähermesser an. Also wird das ganze eine Höhenverstellung für einen Rasenmäher. Daher reicht die Genauigkeit von 3mm auch genau aus.

Beste Grüße,
Chris

Hallo,
na ja wenn Du der Meinung bist es geht nur mit einem Regler, dann versuch Dich mal mit der PID Lib. Wenn Dein Istwert ein Totband hat dann ist das eine "Lose", damit neigt das Ding zum Schwingen.

Man kann auch eine Rampenfunktion für einen Motoransteuerung bauen. Ein Dimmer für eine LED ist ja nichts anderes. Dabei läuft der Motor an einer Rampe entlang bis die Solldrehzahl erreicht ist, bzw. an der Rampe entlang runter bis er steht. Das kann man ganz soft einstellen und ist wesentlich einfacher als einen Regelkreis zu verwenden der ständig im Eingriff ist, was Du ja sowiso nicht willst. Regelkreis auftrennen , damit der Motor aus ist , ist schlecht, aber das hatte ich Dir bereits geschrieben.

Heinz

dann ermittelst halt während der Rampe laufend eine neue Geschwindigkeit und erhöhst bis zur maximal Geschwindigkeit/verringerst bis zur minimal Geschwindigkeit/Stopp

Genau! Da bin ich schon unterwegs.
Ich habe was bei homofaciens.de gefunden.
Damit habe ich erste Erfolge erzielt. Es gefällt mir aber noch nicht so richtig.
Es ist ein PID Regler mit Totband, der schon funktioniert.
Nun habe ich auch die Strategie verstanden (Abweichung berechnen und die verschiedenen (PID) Strategien die Geschwindigkeit zu berechnen).
Allerdings gefällt mir das Verhalten nicht.
Daher werde ich das so ändern wie noiasca gerade geschrieben hat.

Besten Dank und beste Grüße,
Chris