Управление шаговым двигателем через роторный энкодер принтера
- Войдите на сайт для отправки комментариев
Здрасссте умники и умники!
Кто подскажет где криво. пробовал и библиотеки и прерывания. Смысл данный код синхронизирует шаговый двигатель и двигатель dc принтера через роторный энкодер принтера. Проблема в следующем при больших скоростях шаговый двигатель теряет шаги (не запаздывает). Либо может правильнее выразится за короткие интервал времени большое количество значений с энкодера не успевает считать. в общем единственная наверное проблема которую так и не могу найти решение. за кривой код ссорян. Писал как мог.
итог если печатать на листе а4 с заполнением только в начале или конце листа пропуск в середине листа белый сделать не получится. пример на фото.
плату использую стм32 тк помощней пишу в платформио
так должно быть
а так на выходе при печати с пропуском шагов
драйвер шагового двигателя 6600 шаги 32 и 16 пробовал двиг нэма17. либо с энкодера не успевает считать либо код кривой. поможите разобраться
#include <Arduino.h> #include <AccelStepper.h> //#include <GyverEncoder.h> /* #include <Encoder.h> */ #define encoder_pin_A PA9 //считываем энкодер #define encoder_pin_B PA8 //считываем энкодер int encoder_pin_A_last = LOW; long encoder_pos = 0;//int int n = LOW;//int #define stepper_pin_step PA11 #define stepper_pin_dir PA10 // Enc have 24 steps per revolution // The motor have 800 steps per revolution // Want: 1 encoder rev = 1 stepper rev // 800 / 24 = 33.3333333333... float steps_per_pulse = 0.6; AccelStepper stepper(1, stepper_pin_step, stepper_pin_dir); //Encoder enc1(encoder_pin_A, encoder_pin_B); unsigned long stepper2OnTime; #define step_pin 34 #define dir_pin 35 #define buttonhome PB3 #define buttonload PB4 int stepState = LOW; const long interval = 1; const int limitswitchhome = PA15; //концевик позиции печать const int limitswitchload = PA12; //концевик загрузки листа const int limitswitchhead = PB11; //концевик положения печатающей головки const int greendiode = PB10; const int papersensor1 = PB6; //датчик лотка бумаги для симуляции const int papersensor2 = PB5; //датчик бумаги для симуляции unsigned long led2OnTime; bool led2On; bool led1On; bool ledOff; bool timer = false; bool timer2 = false; bool lastButton = false; //bool lastButton2 = false; bool status_limitswitch1; bool status_led1; bool status_led2; int timeOff; int timeOff2; bool movehome = false; bool moveload = true; long positionhome = 0; bool encoderen = false; bool print = false; void limitswitch(){ if (digitalRead(limitswitchhome) == LOW){ //timeOff = 0; //timeOff2 = 0; if(movehome){ movehome = false; positionhome = 0; stepper.setCurrentPosition(0); encoder_pos = 0; } } if (digitalRead(limitswitchload) == LOW){ timeOff = 0; timeOff2 = 0; encoderen = false; timer2 = false; if(moveload){ moveload = false; positionhome = 0; stepper.setCurrentPosition(0); encoder_pos = 0; encoderen = false; } } /* if (digitalRead(limitswitchhead) == HIGH){ lastButton2 = true; } else{ lastButton2 = false; } */ if (digitalRead(limitswitchhead) == LOW && lastButton == true){ timer = true; led2OnTime = millis(); } if(timer){ timeOff = 300000; timeOff2 = 1200; lastButton = false; encoderen = true; if (millis() - led2OnTime >= 7000){ encoderen = true; digitalWrite(papersensor1, HIGH); digitalWrite(papersensor2, LOW); led2On = true; led1On = true; led2OnTime = millis(); timer = false; } } if(led2On){ if(millis() - led2OnTime >= timeOff2) { digitalWrite(papersensor1, LOW); } } if(led1On){ if(millis() - led2OnTime >= 200) { digitalWrite(papersensor2, HIGH); if(millis() - led2OnTime >= timeOff) { digitalWrite(papersensor2, LOW); led1On = false; } } } } void buttons(){ if(movehome){ encoderen = false; stepper.moveTo(positionhome); positionhome++; } if(moveload){ encoderen = false; stepper.moveTo(positionhome); positionhome--; } if (digitalRead(buttonhome) == LOW && digitalRead(buttonload) == HIGH && digitalRead(limitswitchhead) == HIGH){//red button lastButton = true; encoderen = false; positionhome = 0; stepper.setCurrentPosition(0); movehome = true; moveload = false; } if (digitalRead(buttonhome) == HIGH && digitalRead(buttonload) == LOW){//green button lastButton = false; encoderen = false; positionhome = 0; stepper.setCurrentPosition(0); movehome = false; moveload = true; } } /* void encode () { if(encoderen){ if (enc1.isRight()) encoder_pos--; //if (enc1.isLeft()) encoder_pos++; stepper.moveTo((long) round(encoder_pos*steps_per_pulse)); } } */ void encoder(){ if(encoderen){ // read encoder n = digitalRead(encoder_pin_A); if ((encoder_pin_A_last == LOW) && (n == HIGH)) { if (digitalRead(encoder_pin_B) == LOW) { encoder_pos--; } else { // encoder_pos++; //движение энкодером в обратную сторону не нужно } // set stepper to the new calculated position stepper.moveTo((long) round(encoder_pos*steps_per_pulse)); } encoder_pin_A_last = n; } } void setup(){ stepper.setMaxSpeed(225000); stepper.setAcceleration(225000); //stepper.setSpeed(900000); attachInterrupt(digitalPinToInterrupt(PA9), encoder, CHANGE); attachInterrupt(digitalPinToInterrupt(PA8), encoder, CHANGE); pinMode(encoder_pin_A, INPUT); pinMode(encoder_pin_B, INPUT); pinMode(step_pin, OUTPUT); pinMode(dir_pin, OUTPUT); pinMode(buttonhome, INPUT_PULLUP); pinMode(buttonload, INPUT_PULLUP); pinMode(papersensor1, OUTPUT); pinMode(papersensor2, OUTPUT); pinMode(limitswitchhome, INPUT_PULLUP); pinMode(limitswitchload, INPUT_PULLUP); pinMode(limitswitchhead, INPUT); pinMode(greendiode, OUTPUT); encoderen = true; led2On = false; led1On = false; timer = false; } void loop(){ if(lastButton == true){ digitalWrite(greendiode, HIGH); } else{ digitalWrite(greendiode, LOW); } //encode(); //encoder(); //enc1.tick(); stepper.run(); //encoder(); //enc1.tick(); limitswitch(); stepper.run(); //encoder(); //enc1.tick(); stepper.run(); buttons(); //enc1.tick(); stepper.run(); //encoder(); } /* //stepper2 if (digitalRead(button1) == LOW || digitalRead(button2) == LOW) { // ako ni jedan taster nije pritisnut digitalWrite(step_pin, LOW); digitalWrite(step_pin, LOW); } if (digitalRead(button1) == LOW && digitalRead(button2) == HIGH){ digitalWrite(dir_pin, LOW); if (millis() - stepper2OnTime >= interval) { // save the last time you blinked the LED stepper2OnTime = millis(); // if the LED is off turn it on and vice-versa: if (stepState == LOW) { stepState = HIGH; } else { stepState = LOW; } // set the LED with the ledState of the variable: digitalWrite(step_pin, stepState); } } if (digitalRead(button1) == HIGH && digitalRead(button2) == LOW){ digitalWrite(dir_pin, HIGH); if (millis() - stepper2OnTime >= interval) { // save the last time you blinked the LED stepper2OnTime = millis(); // if the LED is off turn it on and vice-versa: if (stepState == LOW) { stepState = HIGH; } else { stepState = LOW; } // set the LED with the ledState of the variable: digitalWrite(step_pin, stepState); } } */ //-------------------------------
ВИДЕО работы на ютубах выложил чтобы было представление
https://www.youtube.com/watch?v=oQM2q5BcHz4
Я не вижу в коде, в каком месте идёт синхронизация.
считывается энкодер при вращении принтера двигателя
#define encoder_pin_A PA9 //считываем энкодер
#define encoder_pin_B PA8 //считываем энкодер
далее высчитывается позиция
181
void
encoder(){
182
if
(encoderen){
183
// read encoder
184
n = digitalRead(encoder_pin_A);
185
if
((encoder_pin_A_last == LOW) && (n == HIGH)) {
186
if
(digitalRead(encoder_pin_B) == LOW) {
187
encoder_pos--;
188
}
else
{
189
// encoder_pos++; //движение энкодером в обратную сторону не нужно
190
}
191
// set stepper to the new calculated position
192
stepper.moveTo((
long
) round(encoder_pos*steps_per_pulse));
193
}
194
195
encoder_pin_A_last = n;
196
}
197
}
и с помощью библиотеки аксельстеппер вращает шаговик
Это не синхронизация.
Это херь какая то
отчасти это понятно. как можно реализовать?
Ну во первых нужно подумать над тем, действительно ли нужна такая точность(4 импульса, на одну риску энкодера) в такой системе.
Если нужна, тогда переписать на быстрый опрос по кодам Грея и массиву значений.
Если не нужна, тогда можно оставить один пин на прерывании по спаду или фронту и код опроса приобретет такой вид:
void EncoderISR(){digitalRead(EncB)?enc_pos++:enc_pos--;}
Во вторых не нужно следить за всем сразу, просто шагаем, когда энкодер не досчитал до позиции.
Если хочется следить сразу за всем, то делать это не на ходу , а по факту: отшагали положеное, сравнили с тем, что насчитал энкодер, не совпало , шагаем ещё на разницу. И тд.
Иначе при такой скорости, частоте опроса и ОГРОМНОМ КОДЕ внутри прерывания , никогда не получим нужного результата.
вот в этом и вопрос у меня возник почему если сигнал весь захватил с энкодера почему его не воспроизводит на шаговик а тупо теряет шаги и все. значит проблема в считывании с энкодера?
не может же библиотека популярная адманывать на шаги)
использовать attachinterrupt сгодится?
попробую считать количество шагов с энкодера
Кстати , если работать с стм32 через адекватный софт, а не через патч Ардуино ИДЕ, то у нее даже пины есть аппаратные под энкодер заточенные.
я так понимаю и результат будет соответствующий?
смогу ли только на адекватном софте вот в чем вопрос)?
подобный код использовали на есп32 отрабатывает поинтересней но все равно шаги просто теряются
Настрой аксельстеппер нормально а энкодер вообще выкинь, он тут ни к чему.
написал на прерываниях пока что с библиотекой аксельстеппер. также настроил библиотеку корректно пока что тестирую спасибо огромное