Hi
Bin momentan dabei, meiner Drehbank einen automatischen Vorschub zu verpassen.
Inspiriert durch dieses YT-Video, nach gebaut mit ALPS-Encoder (15 Rasten a 4 Impulse), als Stepper einen 28BYJ-48 (4096 Steps, etwas schwachbrüstig) befeuert durch die MoBaTools vom microbahner hier aus dem Forum.
Die Aufnahme der Encoder-Signale geschieht per Interrupt (beide Signale mit der gleichen Routine).
Hoffe, ich habe nicht zu sehr mit Kommentaren gegeizt und vll. kann sogar Wer Was Damit anfangen.
Ist Momentan vll. eine Beta, die Warnung zur Zeile 130 kann ignoriert werden, der Wert wird bei Start global auf 0 gesetzt und ist somit definitiv vor der ersten Verwendung bekannt.
/*
Nachbau von 'Lathe Electronic Leadscrew'
https://www.youtube.com/watch?v=FTs9GygRQ-U
Verwendeter Derehencoder von ALPS, liefert 4 Impulse pro Rastung, 15 Rastungen pro Umdrehung
=60 Impulse pro Umdrehung.
Die verwendeten MoBaTools nehmen die Zielposition des Stepper als Winkel entgegen (unter Anderem).
Bei Faktor=6 und Teiler=1 entspricht die Encoder-Umdrehung der Stepper-Umdrehung (60x6=360)
Bei Faktor=90 und Teiler=1 entspricht jede Rastung einer Umdrehung (4 Impulse x 90 = 360°)
Faktor=60 und Teiler=10 entspricht Faktor=6 und Teiler=1, man kann so auf 10.tel Grad runter
Umschalten zwischen den Einzelwerten durch Button-Betätigung, per Software entprellt.
Aufnahme der Encoder-Phasen per Interrupt (beide Signale in der gleichen Routiene).
Davon verspreche ich mir, keinen Wechsel zu verpassen - als Encoder ist ein anderes Modell
mit meeehhhrrrr Impulsen pro Umdrehung angedacht (und ohne Rasten).
Allerdings ist ein Modell mit 4096 Impulsen/Umdrehung für einen Versuch doch etwas teuer - es
wird daher vorerst ein Modell mit 400 Impulsen/Umdrehung.
Wie in dem ver-url-tem Video soll der Kram irgend wann Mal an meine Drehbank und schnieke
Gewinde oder allgemein einstellbare Vorschübe ermöglichen, was bisher nur durch Tausch der Wechselräder
funktioniert.
... to be continue ...
V1_1
Teiler und Faktor sind per Encoder einstellbar
Berechnung auf int64_t gesetzt, jetzt klappt's auch mit den Faktoren
Bei Button-Betätigung werden Winkel, Faktor und Teiler ausgegeben, wie
der aktive Part per * angezeigt, somit ist das 'Übersetzungsverhältnis'
so weit integriert. Adaption auf anderen Stepper/Treiber fehlt, MoBaTools soll bleiben
*/
const byte pin_phase_a = 2; //Phase A des Encoder
const byte pin_phase_b = 3; //Phase B des Encoder
const byte pin_button = 5; //Button des Encoder, Umschalten zwischen Wert und Faktor
volatile uint32_t counter = 0; //Zählwert des Encoder
volatile boolean change = false;
uint32_t counteroffset = 0; //Offset, ab wann der aktuelle Faktor gilt
uint32_t winkeloffset = 0; //Offset des Winkel zum Counteroffset
int32_t winkelwert = 0; //berechneter Winkel zum Counteroffset
int32_t faktor = 6; //Faktor, mit Dem der Counter in den Winkel eingeht -> Encoderumdrehung=Stepeprumdrehung
uint32_t teiler = 1; //Teiler zum Faktor, um den Faktor z.B. in 100.stel anzunehmen
byte wtc = 0; //'what to change' 0=Winkel, 1=Faktor, 2=Teiler einstellen
uint32_t lastbutton = 0; //millis()-Wert der letzten Button-Änderung
const boolean pressed = LOW; //Pinzustand bei gedrücktem Button
boolean buttonpressed = !pressed; //letzte Zustand des Button
const uint32_t debouncetime = 20; //Entprellzeit in ms
#include <MobaTools.h>
Stepper4 Step1(4096); // HALFSTEP ist default, Anzahl an (Halb)Schritten für volle Umdrehung
// Es soll auch 28BYJ-48 geben mit krummen Übersetzungsverhältnis!
// Meine sind aber Alle 4096 Step/Umdrehung (gemessen/gezählt)
//Konstanten für Stepper
const byte maxspeed = 150; //Umdrehungen x10 pro Minute
const uint16_t maxacc = 5; //Je weniger, desto schneller Beschleunigung
void setup() {
Serial.begin(115200);
pinMode(pin_phase_a, INPUT_PULLUP);
pinMode(pin_phase_b, INPUT_PULLUP);
pinMode(pin_button, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pin_phase_a), ISR_phase, CHANGE);
attachInterrupt(digitalPinToInterrupt(pin_phase_b), ISR_phase, CHANGE);
Step1.attach( 9, 8, 7, 6 ); // Anschluß an digitalen Ausgängen; Treiber IN1,IN2,IN3,IN4
Step1.setSpeed( maxspeed ); // = 24 U/Min
Step1.setRampLen(maxacc); // Beschleunigung
Step1.setZero(); // Referenzpunkt f�r Motor 1 setzen
}
void loop() {
// put your main code here, to run repeatedly:
static uint32_t counterwert;
if (change) {
//Es wurde ein Interrupt ausgeführt
do {
change = false; //Flag löschen
counterwert = counter; //Wert auf Variable übergeben
} while (change == true); //wenn während Dessen die ISR aktiv war, erneut einlesen
uint32_t abstand = 0;
if (counterwert > counteroffset) {
abstand = counterwert - counteroffset;
} else {
abstand = counteroffset - counterwert;
}
switch (wtc) {
case 0://Winkel soll am Counterwert hängen
winkelwert = -int64_t(counterwert - counteroffset) * faktor / teiler + winkeloffset;
Step1.write(winkelwert); //counterwert 60 pro Umdrehung, Ziel-Winkel an Stepper
Serial.print("Zielwinkel:");
Serial.println(winkelwert);
break;
case 1://Faktor soll am Counterwet hängen
//counter, counteroffset, faktor
if (abstand >= 4) {
faktor = faktor + int32_t(counterwert - counteroffset) / 4;
counteroffset = counterwert;
}
Serial.print("Faktor:");
Serial.println(faktor);
break;
case 2://Teiler soll am Counterwert hängen
//counter, counteroffset, faktor
if (abstand >= 4) {
if (-int32_t(counterwert - counteroffset) / 4 >= int32_t(teiler)) {
teiler = 1;
} else {
teiler = teiler + int32_t(counterwert - counteroffset) / 4;
}
counteroffset = counterwert;
}
Serial.print("Teiler:");
Serial.println(teiler);
break;
default://zurück auf Anfang
wtc = 0;
break;
}
}
byte isbuttonpressed = digitalRead(pin_button);
if (isbuttonpressed != buttonpressed) {
if (millis() - lastbutton >= debouncetime) {
lastbutton = millis();
if (isbuttonpressed == pressed) {
//Button ist gedrückt, kommt beim ersten Mal durch, dann für debouncetime nicht mehr
wtc = ++wtc % 3;
if (wtc==0) Serial.print('*');
Serial.print("Winkel\t");
if (wtc==1) Serial.print('*');
Serial.print("Faktor\t");
if (wtc==2) Serial.print('*');
Serial.print("Teiler\n");
Serial.print(winkelwert);
Serial.print('\t');
Serial.print(faktor);
Serial.print('\t');
Serial.println(teiler);
counteroffset = counterwert; //Offset neu setzen
winkeloffset = winkelwert; //Offset nur für Winkel relevant, müsste aber in 'Teiler' stehen und ändert sich sonst nicht
}
}
buttonpressed = isbuttonpressed; //neuen Zustand übernehmen
}
/*
// Herzschlag
static boolean printflag = false;
if (millis() - lastmillis >= 1000) {
lastmillis += 1000;
if (!printflag) { //nur 1x alle Sekunde ausgeben
Serial.print('+');
Serial.println(counter);
printflag = true;
}
} else {
printflag = false;
}
*/
}
/*
//bei oberem Bit==1 untere Bit umdrehen, so bekommen wir eine zählbare Reihenfolge zum Encoder-Bit-Muster
//PLUS //MINUS
11 (10) 11 (10)
10 (11) 01 (01)
00 (00) 00 (00)
01 (01) 10 (11)
*/
void ISR_phase(void) {
//untere Bit
byte static old_wert = 2; //keine Phase aktiv, Beide per PullUP hochgezogen, untere Bit umgedreht
byte new_wert = digitalRead(pin_phase_b) << 1 | digitalRead(pin_phase_a);
if (new_wert & 0x02) new_wert ^= 0x01; //wenn oberes Bit gesetzt ist, das Untere umdrehen
if (new_wert == ((old_wert + 1) & 0x03)) counter++;
if (old_wert == ((new_wert + 1) & 0x03)) counter--;
old_wert = new_wert;
change = true; //Änderung in der loop() anzeigen
}
Jetzt fehlt 'nur noch' das Aufpumpen auf einen ordentlichen Stepper und der andere Encoder.
... neben dem mechanischem Umbau der Drehe ... Was wohl, wie ich mich kenne, noch etwas dauern wird ...
MfG
Edit Arduino-NANO
#ALPS, #Encoder, #LeadScrew, #Längsvorschub, #Drehbank, #Lathe, #Stepper, #MoBaTools