Zurück zum Inhaltsverzeichnis
Um ein paar Schrittmotoren zu testen, brauchte ich ein Testgerät.
Ich habe dann mal ein bißchen exprimentiert und bin dann auf folgende Lösung(en) gekommen.
Dazu noch eine Anmerkung: Auf der Seite von ReRap über das Breakoutboard TMC2100
werden verschiedene Bilder der Treiberkarte gezeigt, das Bild mit der Beschriftung "Pin-Belegung" ist aber fehlerhaft.
Der "dir"-Pin liegt nicht auf dem Ende der Karte an dem auch das Poti einelötet ist, also Achtung.
Soll-Vorgaben
Es sollte:
- eine über ein Poti regelbare Geschwindigkeit haben
- Rechts- und Linkslauf haben
- Über eine Rampe hochgefahren werden
- Optional eine Anzeige zur eingestellten Geschwindigkeit
Vorhandene Hardware
Benötigt werden:
- Ein ESP32 (Fast egal, Hauptsache er läßt sich programmieren)
- Ein Treiberbaustein auf Basis TMC2100
- Schrittmotor (hier: JANOME 4SQ-120B)
- 5 LEDs
- 5 Widerstände 1kΩ
- 2 Widerstände 10kΩ
- 1 Elko 100µF
- 1 Poti (1kΩ)
- 1 Taster 2*ein mit Mittelstellung
- 1 Step-Down-Spannungsregler für 3.3V des ESP32
- 1 12V oder 24V Schaltnetzteil
- Bei einem 12V Netzteil könnte der Motor zu wenig Drehmoment haben.
Diverse Ideen
Optional:
- 1 LC-Display 16*2 in gruen/gelb oder in blau/weiss
- 1 I2C-Modul für das Display
- 1 Step-Down-Spannungsregler für 5V des Display
- 1 2-Kanal Levelshifter(bidirektional) Roboter Bausatz Shop, Watterott, Sertronics
Minimale Ausstattung
- Die 5 Leuchtdioden mit den 1kΩ Widerständen (R1-R5) dienen erstmal nur zur Anzeige zum Testen ohne Motor
- Die LC-Anzeige kann ebenfalls entfallen, der Motor läuft auch ohne
- Wird der ESP32 von einem anderen Rechner angesteuert, kann der Taster und die beiden 10kΩ Widerstände (R6,R7) entfallen
Schaltpläne
Breadboard
Nun zur Schaltung auf dem Breadbord:
Der Step-Down-Spannungsregler (12V/24V -3.3V ist aus Platzmangel hier nicht eingezeichnet:
Der untere Teil des Breadboards ist die 3.3V-Schiene, die obere Schiene ist für 12V, beide sind über GND miteinander verbunden
Die Leitungen sind farblich gekennzeichnet:
Rot + 3.3V
Cyan + 12V
Blau GND
Schwarz Motorleitungen
Grün Taster und Mittelanzapfung des Potis
Violet Drehrichtungsanzeige
Braun Steuer- und Anzeigeleitungen des TMC2100
Anstelle des Tasters habe ich eine 3 pol. Stiftleiste eingefügt, aber der Taster, den ich benutzt habe fand sich nicht in der Library von Fritzing.
Normaler Schaltplan
Und nun noch der Schaltplan, auch hier gibt es die gleiche Farbzuordnung.
Eigentlich nichts besonderes.
Die Leiterplatte
Ich habe mir mal die Mühe gemacht eine Leiterplatte zu entwerfen. Ein Test bei Fritzing ergab einen Preis von etwa 34€ für 3 Stück.
Erst das Layout, dann Bestückungsseite und die Lötseite
Und hier noch die Fritzing-Dateien zum selbermachen: Schrittmotor.zip
Wo kann man eigentlich bei Fritzing die Leiterbahnbreite einstellen?
Zusätzliche Option
Falls jemand noch den I2C-Bus anschliessen möchte, SDA liegt an IO21 und SCL an IO22.
Hier kann man hier noch ein 1602-LCDisplay anschliessen. Die entsprechende Software ist bereits vorbereitet,
benötigt wird nur eine Anzeige, das I2C-Modul und ein zweikanaliger Levelshifter.
Angezeigt wird allerdings nur die Stellung des Potis zwischen ganz langsam (1) und höchstmöglichen Geschwindigkeit(1000).
Software
Erstellt wurde die Firmware mit Hilfe der Arduino-IDE, wie man die ESP32 Umgebung einrichtet, wird woanders besser beschrieben.
/*
Schrittmotortester mit ESP32
Entwickelt mit Arduino-IDE
Motortreiber TMC2100
Regelbare Geschwindigkeit
Taster 1 * um mit Mittelstellung "(um) aus (um)"
20181219 Erste Lauffähige Version Jürgen Böhm
*/
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_I2C.h> // LiquidCrystal_I2C Bibliothek einbinden
LiquidCrystal_I2C lcd(0x27, 16, 2); // Hier wird festgelegt um was für einen Display es sich handelt.
//16 Zeichen in 2 Zeilen und der HEX-Adresse 0x27.
//Für ein vierzeiliges I2C-LCD verwendet man den Code "LiquidCrystal_I2C lcd(0x27, 20, 4)"
#define Poti 34 // Mittelanschluss des Potis
#define Taster_1 32 // Taster-Pin links
#define Taster_2 33 // Taster-Pin rechts
#define LED_1 13 // LED-Pin links
#define LED_2 12 // LED-Pin rechts
int stepPin = 25;
int dirPin = 26;
int enablePin = 27;
int sleepPin = 14; // Vorbereitet, aber nicht angeschlossen
// Die meisten Variablen sind global, damit die Schleife schneller läuft
// Und man muss nicht lange suchen
int left = 0;
int right = 0;
int Entprellzeit = 20; // (ms) Wartezeit fürs Tastenprellen
int potValue = 0; // Wert des AD-Wandlers
unsigned long lastInterruptTime; // Zählvariable für Tasterinterrupt
uint32_t Rampe = 1; // Zählvariable für Rampe
uint32_t RAMPE = 200; // (μs) Fester Wert für eine Rampe, damit Motor sanft hochfährt.
uint32_t Delay_on = 100; // (μs) Minimale Zeit, die der StepPin auf "High" sein muss
uint32_t Delay_off = 1600; // (μs) Minimale Zeit, die der StepPin auf "Low" sein muss
int val = 0; // temporaer
int val_1 = 0; // temporaer
int val_2 = 0; // temporaer
void setup()
{
// Serielle Schnittstelle einstellen
Serial.begin(115200);
MOTOR_init();
LCD_init();
PIN_init();
}
void PIN_init() // Interrupt für die Taster vorbereiten
{
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
// Interrupt für 2 Taster einstellen
pinMode(Taster_1, INPUT_PULLUP);
pinMode(Taster_2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(Taster_1), Taster_links, CHANGE);
attachInterrupt(digitalPinToInterrupt(Taster_2), Taster_rechts, CHANGE);
}
void LCD_init() // LCD initialisieren
{
lcd.init(); // Im Setup wird der LCD gestartet
lcd.backlight(); // Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
// Ab hier ist das eigentlich nur Quatsch
/*
lcd.setCursor(0, 0);
lcd.print(" Init"); // Erste Zeile
delay(1000); // Nur eine Sekunde
lcd.setCursor(0, 1);
lcd.print(" Ruhig, Brauner"); // Zweite Zeile
delay(1000); // Nur eine Sekunde
lcd.clear();
*/
lcd.setCursor(0, 0);
lcd.print(" Ich bin wieder "); // Erste Zeile
lcd.setCursor(0, 1);
lcd.print("da, Guten Morgen"); // Zweite Zeile
delay(1000); // Nur eine Sekunde
lcd.clear();
}
void MOTOR_init()
{
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enablePin, OUTPUT);
pinMode(sleepPin, OUTPUT);
digitalWrite(dirPin, LOW);
digitalWrite(stepPin, LOW);
stopMotor(enablePin, sleepPin, dirPin);
}
void stopMotor(int &enablePin, int &sleepPin, int &dirPin)
{
digitalWrite(enablePin, 1); // Enable is inverted. HIGH means the motor is disabled.
digitalWrite(sleepPin, 0); // Sleep is inverted. LOW means the driver sleeps.
digitalWrite(dirPin, 0);
Rampe = RAMPE;
}
void loop()
{
// Nochmal eine Sicherheitsverriegelung
// Erstmal ob die Taster aus sind
val_1 = digitalRead(Taster_1);
val_2 = digitalRead(Taster_2);
if (val_1 == 0 && val_2 == 0) // Nur wenn beide Taster aus sind
{
left = 0;
right = 0;
digitalWrite(LED_1, 0);
digitalWrite(LED_2, 0);
// Debug
// Serial.println("Taster aus ");
}
// Poti abfragen und auf 0 - 40000 mappen
// Man braucht so eine lange Zeit, damit der Motor auch ganz langsam läuft
potValue = map(analogRead(Poti), 0, 4096, 0, 40000);
if (left == 1 && right == 0) // Links
{
digitalWrite(dirPin, HIGH);
digitalWrite(enablePin, LOW);
digitalWrite(stepPin, HIGH);
delayMicroseconds(Delay_on);
digitalWrite(stepPin, LOW);
delayMicroseconds(Delay_off + Rampe + potValue);
if (Rampe > 0)
{
--Rampe;
}
// Debug
// Serial.println(Rampe);
}
if (left == 0 && right == 1) // Rechts
{
digitalWrite(dirPin, LOW);
digitalWrite(enablePin, LOW);
digitalWrite(stepPin, HIGH);
delayMicroseconds(Delay_on);
digitalWrite(stepPin, LOW);
delayMicroseconds(Delay_off + Rampe + potValue);
if (Rampe > 0)
{
--Rampe;
}
//Debug
// Serial.println(Rampe);
}
if (left == 0 && right == 0) //Alles aus
{
digitalWrite(dirPin, LOW);
digitalWrite(enablePin, HIGH);
digitalWrite(stepPin, LOW);
// Ausgabe auf einer LCD nur im Stillstand
lcd.setCursor(0, 0);
lcd.print(" Geschwindigkeit");
char buffer[7];
lcd.setCursor(12, 1);
sprintf(buffer,"%4i",(1000-(potValue/40)));
lcd.print(buffer);
//Debug auf LCD
// lcd.setCursor(0, 1);
// sprintf(buffer,"%5i",Delay_off + Rampe + potValue);
// lcd.print(buffer);
Rampe = RAMPE;
}
//Debug
//Serial.println(Rampe);
}
// Die beiden Interruptroutinen zum Entprellen der Tasten
void Taster_links() {
val = digitalRead(Taster_1);
unsigned long interruptTime = millis();
/* Wenn die Interrupts in Folge schneller wie XXms auftreten,
werden diese als Prellen erkannt und letztendlich ignoriert */
if (interruptTime - lastInterruptTime > Entprellzeit) {
if (val == 1)
{
// Über die Software verriegeln
digitalWrite(LED_1, 1);
digitalWrite(LED_2, 0);
right = 0;
left = 1;
Rampe = RAMPE;
}
else
{
digitalWrite(LED_2, 0);
digitalWrite(LED_1, 0);
left = 0;
right = 0;
}
// Speichert den aktuellen Zeitstempel
lastInterruptTime = interruptTime;
}
}
void Taster_rechts() {
val = digitalRead(Taster_2);
unsigned long interruptTime = millis();
/* Wenn die Interrupts in Folge schneller wie XXms auftreten,
werden diese als Prellen erkannt und letztendlich ignoriert */
if (interruptTime - lastInterruptTime > Entprellzeit) {
if (val == 1)
{
digitalWrite(LED_2, 1);
digitalWrite(LED_1, 0);
left = 0;
right = 1;
Rampe = RAMPE;
}
else
{
digitalWrite(LED_2, 0);
digitalWrite(LED_1, 0);
left = 0;
right = 0;
}
// Speichert den aktuellen Zeitstempel
lastInterruptTime = interruptTime;
}
}
Alles anzeigen
Beschreibung der Software
Die Library "Wire.h" wird für den I2C-Bus gebraucht, die Lib "LiquidCrystal_I2C.h" zum Ansteuern der Anzeige.
Darunter folgen die IOs (nicht die Pins) an dem die LEDs, Taster und der Motortreiber angeschlossen wird.
Danach folgen eine Reihe globaler Variablen, global aus Geschwindigkeitsgründen. An folgenden Variablen kann gedreht werden:
- (ms) Entprellzeit wird in den Interrupt-Routinen als Entprellzeit benutzt
- (μs) mit RAMPE wird ein Zähler gestellt, der den Schrittmotor von einer niedrigen Drehzahl auf die Soll-Drehzahl beschleunigt
- Kann bei massearmen Motoren entfallen. Wenn sich der Motor sich nicht bewegt und nur brummt kann man hier dran drehen
- (μs) Delay_on stellt die Zeit, mit der der Step-Pin des TMC2100 minimal "HIGH" sein muss
- Zu niedrige Werte bemerkt man hier wenn der Motor Schritte verliert und "ruppig" läuft
- (μs) Delay_off stellt die Zeit, mit der der Step-Pin des TMC2100 minimal "LOW" sein muss
- Zu niedrige Werte bemerkt man hier wenn der Motor Schritte verliert und "ruppig" läuft
Ansonsten wird die Drehgeschwindigkeit nur durch "void loop()" bestimmt.
In der "void loop()" ist nochmal eine Verriegelung vorgesehen weil es hier mehrmals vorgekommen ist die Variable left oder right
trotz loslassen des Taster auf HIGH geblieben sind. Somit wäre der Motor einfach weitergelaufen.
Die Anzeige wird nur während des Motorstillstands aktualisiert,
jetzt ist es nur die Enstellung des Potis, im Bereich von 1 - 1000.
Wenn man aber die 3 Zeilen unter "//Debug auf LCD" aktiviert, sieht man den gesamten "Delay_off" + "Rampe".
Die Aktualisierung der Anzeige über den I2C-Bus braucht sehr viel Zeit und verzögert die Geschwindigkeit des Motors erheblich.
Die Geschwindigkeit kann man aber regeln während der Motor läuft.
Die anderen Zeilen unter "//Debug" sind für die serielle Konsole gedacht, sie wurde in der "void setup()" mit 115200 Baud voreingestellt.
Fazit
Die Ansteuerung eines Schrittmotors funktioniert, ist aber nicht der Renner.
Für Prüfzwecke brauchbar wenn keine hohen Geschwindigkeiten gefordert werden.
Der ESP32 ist hier einfach nicht schnell genug. Es ist aber durchaus möglich, das sich die Software noch optimieren läßt.
Ärgerlich war das falsche Anschlussbild bei ReRap, das einen ESP32-Pico und ein TMC2100-Board den magischen Rauch aus der Schaltung freigelassen hat.
MfG
Jürgen
Edit: Ich vergass die Quelle der Schrittmotoren: Und wieder nahm das jährliche Ritual unserer Firma seinen Lauf,
Edit_2: Pläne ausgetauscht, Layout und Fritzing-Archiv hinzugefügt.
Edit_3: Fehler in der Beschreibung korrigiert, der sich mit neuen Software eingeschlichen hatte.