Управление шаговым двигателем через роторный энкодер принтера

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

Здрасссте умники и умники!

Кто подскажет где криво. пробовал и библиотеки и прерывания. Смысл данный код синхронизирует шаговый двигатель и двигатель 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);
  }
} */
//-------------------------------

 

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

ВИДЕО работы на ютубах выложил чтобы было представление

https://www.youtube.com/watch?v=oQM2q5BcHz4

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Я не вижу в коде, в каком месте идёт синхронизация.

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

Kakmyc пишет:
Я не вижу в коде, в каком месте идёт синхронизация.

считывается энкодер при вращении принтера двигателя

#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

}

и с помощью библиотеки аксельстеппер вращает шаговик

stepper.run();
Kakmyc
Offline
Зарегистрирован: 15.01.2018

Это не синхронизация.
Это херь какая то

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

Kakmyc пишет:
Это не синхронизация. Это херь какая то

отчасти это понятно. как можно реализовать?

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Ну во первых нужно подумать над тем, действительно ли нужна такая точность(4 импульса, на одну риску энкодера) в такой системе.
Если нужна, тогда переписать на быстрый опрос по кодам Грея и массиву значений.
Если не нужна, тогда можно оставить один пин на прерывании по спаду или фронту и код опроса приобретет такой вид:

void EncoderISR(){digitalRead(EncB)?enc_pos++:enc_pos--;}

Во вторых не нужно следить за всем сразу, просто шагаем, когда энкодер не досчитал до позиции.
Если хочется следить сразу за всем, то делать это не на ходу , а по факту: отшагали положеное, сравнили с тем, что насчитал энкодер, не совпало , шагаем ещё на разницу. И тд.

Иначе при такой скорости, частоте опроса и ОГРОМНОМ КОДЕ внутри прерывания , никогда не получим нужного результата.

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

Kakmyc пишет:
Ну во первых нужно подумать над тем, действительно ли нужна такая точность(4 импульса, на одну риску энкодера) в такой системе. Если нужна, тогда переписать на быстрый опрос по кодам Грея и массиву значений. Если не нужна, тогда можно оставить один пин на прерывании по спаду или фронту и код опроса приобретет такой вид: void EncoderISR(){digitalRead(EncB)?enc_pos++:enc_pos--;} Во вторых не нужно следить за всем сразу, просто шагаем, когда энкодер не досчитал до позиции. Если хочется следить сразу за всем, то делать это не на ходу , а по факту: отшагали положеное, сравнили с тем, что насчитал энкодер, не совпало , шагаем ещё на разницу. И тд. Иначе при такой скорости, частоте опроса и ОГРОМНОМ КОДЕ внутри прерывания , никогда не получим нужного результата.

 

вот в этом и вопрос у меня возник почему если сигнал весь захватил с энкодера почему его не воспроизводит на шаговик а тупо теряет шаги и все. значит проблема в считывании с энкодера?

не может же библиотека популярная адманывать на шаги)

использовать attachinterrupt сгодится?

попробую считать количество шагов с энкодера

 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Кстати , если работать с стм32 через адекватный софт, а не через патч Ардуино ИДЕ, то у нее даже пины есть аппаратные под энкодер заточенные.

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

Kakmyc пишет:
Кстати , если работать с стм32 через адекватный софт, а не через патч Ардуино ИДЕ, то у нее даже пины есть аппаратные под энкодер заточенные.

я так понимаю и результат будет соответствующий?

смогу ли только на адекватном софте вот в чем вопрос)?

подобный код использовали на есп32 отрабатывает поинтересней но все равно шаги просто теряются

rkit
Offline
Зарегистрирован: 23.11.2016

Настрой аксельстеппер нормально а энкодер вообще выкинь, он тут ни к чему.

Arduinchlk
Arduinchlk аватар
Offline
Зарегистрирован: 15.03.2021

Kakmyc пишет:
Ну во первых нужно подумать над тем, действительно ли нужна такая точность(4 импульса, на одну риску энкодера) в такой системе. Если нужна, тогда переписать на быстрый опрос по кодам Грея и массиву значений. Если не нужна, тогда можно оставить один пин на прерывании по спаду или фронту и код опроса приобретет такой вид: void EncoderISR(){digitalRead(EncB)?enc_pos++:enc_pos--;} Во вторых не нужно следить за всем сразу, просто шагаем, когда энкодер не досчитал до позиции. Если хочется следить сразу за всем, то делать это не на ходу , а по факту: отшагали положеное, сравнили с тем, что насчитал энкодер, не совпало , шагаем ещё на разницу. И тд. Иначе при такой скорости, частоте опроса и ОГРОМНОМ КОДЕ внутри прерывания , никогда не получим нужного результата.

написал на прерываниях пока что с библиотекой аксельстеппер. также настроил библиотеку корректно пока что тестирую спасибо огромное