DC Motoren-Synchronisierung/-Steuerung mit Pro Mini und L298N Dual H-Brücke

  • Hallo zusammen,


    wie das letzte mal im Tutorial-Thread schon angedeutet, diesmal ein Beispiel für die Verwendung einer L298N Dual H-Brücke, bei dem wir die Drehzahl von zwei DC-Motoren beeinflussen.
    Was ist das Ziel des Ganzen?
    Wir versuchen zwei Elektro-Motoren, deren Drehzahl wir mit jeweils einer Impulsgeber-Scheibe ermitteln, so anzusteuern, dass ihre Drehzahlen möglichst gleich sind.
    Und wozu soll das gut sein?
    Weil es durchaus vorkommen wird, dass zwei Motoren fertigungsbedingt oder durch unterschiedliche Rad-Durchmesser (Reifendruck, unterschiedliche Profiltiefe, ...) nicht unbedingt auch die gleiche Drehzahl haben. Bei einem Fahrzeug mit zwei Motoren als Antrieb würde dieses sonst dauernd eine Kurve machen.
    Um das auszugleichen verwenden wir die doppelte H-Brücke, über die wir nicht nur die Drehrichtung steuern sondern über das Anlegen eines pulsweiten-modulierten Signals (PWM) an den Pins ENA und ENB die Geschwindigkeit jedes der beiden Motoren regeln können.


    Wir benötigen:
    einen Arduino Pro Mini (oder kompatibel)
    eine L298N Dual H-Brücke
    zwei TT Getriebe-Motoren (evtl. auf Chassis Platte)
    zwei zu den Motoren passende Encoder-Scheiben und zugehörigen Gabel-Lichtschranken
    evtl. ein Breadboard das das Verkabeln vereinfacht
    eine Handvoll Jumper-Kabel (aka Dupont-Kabel)
    eine ausreichende Stromversorgung der Motoren (z.B. Akku- oder Batterie-Pack)
    Stromversorgung für den Arduino und die Schaltungslogik des Treiber-Boards


    Der Pro Mini sollte klar sein, als H-Brücke habe ich wieder das Board aus dem Stepper-Thread verwendet (also so was -> hier <-).
    Ich habe die Motoren auf die Grundplatte eines 2WD Robot Car montiert (so was -> hier <-). Das macht die Sache einfacher, weil auch die Impulsgeber direkt auf diese Platte geschraubt werden können.
    Prinzipiell sollte das auch mit zwei beliebigen Gleichstrom-Motoren in beliebigen Chassis funktionieren. Allerdings müsstet ihr dann ggf. die Schaltung und evtl. auch die Software entsprechend anpassen.
    Als Gabel-Lichtschranke wollte ich zuerst so was -> hier <- einsetzen. Aber ...


    Achtung! Bei mir hatten die dem Chassis beigelegten Encoder-Scheiben einen viel zu kleinen Durchmesser, so dass ein Abnehmen der Dreh-Impulse praktisch nicht möglich war. Abhilfe hat da eine andere Impulsgeber-Kombination geschaffen ( HC020K ).


    Wie auch bei der Ansteuerung des Stepper-Motors im anderen Thread entfernen wir den Jumper für die Spannungs-Regelung auf dem L298N-Board.
    Ausserdem entfernen wir die Jumper ENA und ENB ... hier schliessen wir dann unsere PWM-Signale an.



    Nun dann machen wir uns mal an das Verkabeln.
    Im Schaltbild habe ich versucht die Impulsgeber durch die Gabel-Lichtschranken ober- bzw. unterhalb der Motoren darzustellen. Die Stromversorgung des Arduino ist die rote Platine auf dem Breadboard (Breadboard power supply 5V/3.3V) und die der Motoren der Batterie-Pack. Ich hoffe, ihr versteht was gemeint ist.
    Da das Schaltbild eher der Veranschaulichung dienen soll, bitte die Verkabelung so vornehmen wie hier im Folgenden beschrieben. Es ist durchaus möglich, dass das Schaltbild davon abweicht. Falls ihr einen solchen Fehler entdeckt, dann gebt mir bitte bescheid. Richtig ist in jedem Fall die textuelle Beschreibung.


    Zunächst steckt ihr die Breadboard-Versorgung und den Pro Mini auf Euer Steckbrett. Versetzt dabei den Arduino so, dass ihr genügend freie Reihen für die Steuerleitungen habt, sonst wirds schnell unübersichtlich. Jetzt verbindet schon mal den +5V Anschluss des Pro Mini mit der Plus-Leiste und den GND Pin mit deer Minus-Leiste des Breadboards.
    Vermutlich haben Eure Optokoppler (Gabel-Lichtschranken) nur drei Anschlusskabel. Verbindet also jetzt die +5V der Optokoppler mit einer "roten Lane" (durchgehende rote = Plus-Leiste) und dann deren GND-Anschlüsse mit einer "blauen Lane".
    Jetzt verdrahten wir das L298N Board.
    Verbindet den GND-Anschluss (mittlerer Anschluss) mit einer blauen Lane und den +5V Anschluss mit einer roten Lane.
    Jetzt schliesst OUT1 und OUT2 an die beiden Anschlüsse des rechten und OUT3 und OUT4 an die beiden Anschlüsse des linken Motors an.
    Möglicherweise stimmt die Drehrichtung eines oder beider Motoren später nicht. Vertauscht dann einfach die Anschlüsse für OUT1 und OUT2 bzw. OUT3 und OUT4 untereinander.
    Jetzt verbindet

    Code
    In1 mit Pin #9 des Arduino
    In2 mit Pin #8 des Arduino
    In3 mit Pin #7 des Arduino
    In4 mit Pin #6 des Arduino
    ENA mit Pin #5 des Arduino
    ENB mit Pin #4 des Arduino
    den Ausgang des linken Optokopplers mit Pin #3 des Arduino
    den Ausgang des rechten Optokopplers mit Pin #2 des Arduino


    Die Pins #2 und #3 des Arduino habe ich deshalb verwendet, weil sie die einzigen Pins des Pro Mini sind, die ohne grössere Klimmzüge externe Hardware-Interrupts unterstützen.
    Jetzt verbindet noch die Masse des Batterie-Packs mit einer blauen Lane und den Pluspol mit dem +12V Anschluss des L298N Boards.
    Nun, damit sollte alles passen und ich hoffe, ich hab' nichts vergessen. Also nach der Kontrolle noch mal nachsehen, sicherheitshalber noch mal kontrollieren und ... na, ihr wisst schon.


    Doch zunächst noch zur Software im Anhang.
    Ich verwende die MsTimer2-Library, die ihr -> hier <- downloaden könnt. Installiert diese bitte und entpackt das im Anhang enthaltene Archiv am besten in Euer sketchbook-Verzeichnis. Nach dem Start der Arduino-IDE findet ihr das Projekt dann unter "sketchbook -> DCMotor_1".


    Ihr werdet Euch evtl. zunächst über die zusätzlichen Tabs in der IDE wundern.
    Um das Ganze möglichst übersichtlich zu halten, habe ich Impulsgeber und Motortreiber gekapselt und zusätzlich die beiden Motoren in einem Objekt SyncMotor zusammengefasst.
    Doch der Reihe nach.
    HC020K.cpp/.h enthält eine Klasse, die dem Impulsgeber, also der Gabel-Lichtschranke entspricht.
    Hier werden pro Instanz die Impulse einer Lichtschranke gespeichert. Das Zählen erfolgt über eine ISR (Interrupt-Service-Routine) - und zwar etwas tricky - ist aber scheinbar nicht anders zu lösen. Im setup des Hauptprogramms wird einem Interrupt eine Routine zugewiesen, die ihrerseits jetzt die Callback-Funktion des Impulsgebers aufruft:


    In L298N.cpp/.h ist eine Klasse für einen Motor definiert. Genau genommen ist es die Klasse einer H-Brücke (also ein halbes L298N Board).
    Hier finden sich die Methoden die die Steuerleitungen bedienen um einen Motor vorwärts oder rückwärts laufen zu lassen, ihn anzuhalten oder abzubremsen und um seine Drehzahl zu erhöhen oder zu erniedrigen.


    Schliesslich gibt es noch SyncMotor.cpp/.h die zwei Motoren und deren zugehörige Impulsgeber miteinander zu einem "synchronen Antrieb" zusammenfassen.
    Zur Prüfung und Regelung der Drehzahlen wird eine Check-Routine zyklisch aufgerufen. Hier kommt die MsTimer2-Library zum Einsatz. Und auch hier erfolgt der Aufruf wieder sozusagen durch die Hintertür vom setup des Hauptprogramms aus:


    Soviel mal zum groben Überblick.
    Der Ablauf ist jetzt, dass die Motoren anlaufen und die Impulsgeber-Scheiben der Motoren Informationen über die Drehzahl liefern, die mittels Interrupt-Routine erfasst werden.
    Zyklisch alle 500 ms (ist noch fix kodiert in der SyncMotor.cpp) wird jetzt die Auswertungs-Funktion aktiviert, die die aufgelaufenen Impulse pro Motor vergleicht. Über- oder unterschreitet die Differenz einen Schwellenwert (UPPER_TICK_RANGE bzw. LOWER_TICK_RANGE in SyncMotor.cpp) wird über eine Änderung des Duty-Cycle des PWM-Signals nachgeregelt.
    Dabei wird angenommen, dass sich der Duty-Cycle (0 = stop, 255 = Vollgas) innerhalb eines Schwankungsbereichs befinden muss. Die Grenzwerte werden im Moment durch zwei Konstanten definiert (MIN_DUTY_LIMIT bzw. MAX_DUTY_LIMIT in SyncMotor.h).
    Bei einem Sollwert für den Duty-Cycle von 200 muss der reale Duty-Cycle also zwischen Soll-Wert - MIN_DUTY_CYCLE und Soll-Wert + MAX_DUTY_CYCLE liegen.
    Um nachzuregeln wird zunächst der Ist-Wert für das Beschleunigen des zu langsamen Motors berechnet und überprüft. Liegt er ausserhalb des Grenzbereichs wird der zu schnelle Motor verlangsamt.
    Während der Überprüfung und Berechnung wird das weiterzählen der Impulse durch ein Flag unterbunden, zudem werden im Anschluss an Berechnung und Korrektur die Zähler zurückgesetzt.


    Das ist jetzt mal mit der heissen Nadel gestrickt und soll auch nur als Anschauungs-Objekt dienen.


    Falls es nicht auf Anhieb klappt ... das ist jetzt schon etwas komplexer als eine LED blinken zu lassen. Dementsprechend hinterhältig ist auch der Fehlerteufel. Im Zweifelsfall lieber dreimal zu viel als einmal zu wenig kontrolliern.
    Wichtig!
    Die Verbindungen auf dem Breadboard neigen, bei mir zumindest, hin und wieder zu Wackel-Kontakten. Notfalls Schraubklemmen verwenden oder löten.


    Bei Eingängen Pullup-/Pulldown-Widerstände verwenden. Der Arduino verfügt über interne Pullups von 20k, die ganz leicht aktiviert werden können (bitte -> hier <- nachlesen).
    Das hat mir einiges an Mehraufwand beschert, weil ich schlicht und ergreifend nicht mehr daran gedacht habe und mich immer über 2000 Impuls in 10 Sekunden gewundert habe (eine Umdrehung = 20 Impulse).


    Ja, ok, das war's dann ...
    Ich wünsche Euch viel Erfolg/Spass mit dieser Anleitung und hoffe, dass sich die eine oder andere sinnvolle Verwendung dafür findet.
    Bei Fragen, Problemen, Fehlern ... bitte melden.


    //EDIT: Wegen diverser Anfragen habe ich mal zwei Detailfotos der Impulsgeber hinzugefügt.


    So long,
    -ds-

  • Hallo, ich glaube hier ist ein Fehler


    In1 mit Pin #9 des Arduino
    In2 mit Pin #8 des Arduino
    In3 mit Pin #7 des Arduino
    In4 mit Pin #7 des Arduino ??? #6
    ENA mit Pin #5 des Arduino
    ENB mit Pin #4 des Arduino
    den Ausgang des linken Optokopplers mit Pin #3 des Arduino
    den Ausgang des rechten Optokopplers mit Pin #2 des Arduino



    Sonst Super Danke