Проблемы с переводом значений позиционного кодера в RPM с помощью Arduino

#c #c #arduino #encoder

#c #c #arduino #кодировщик

Вопрос:

Я использую кодер 400 PPR с Arduino для измерения значений кодера. Мне удалось заставить энкодер считывать значения 0-400 для положительного вращения и от 0 до -400 для отрицательного вращения и сбрасывать значение на 0, как только энкодер совершает полный оборот. Эта часть моего кода работает, проблема, с которой я сталкиваюсь, заключается в переводе этих позиционных значений в RPM.

Мой подход был таким: я использую функцию millis () для отслеживания общего времени программы и переменную time_now для сохранения этого значения. У меня есть оператор if, который выполняется каждый раз, когда millis() становится больше time_now на REFRESH_RATE (в моем случае это определяется как 1 МС), поэтому выполняется каждые 1 миллисекунду.

Мой следующий подход заключается в том, чтобы брать две выборки каждую миллисекунду. Разница между pointSample1 и pointSample2 должна давать мне количество тактов, которое кодировщик перемещает за 1 мс. Это становится немного сложнее, потому что это, по сути, окружность в 400 градусов, поэтому, например, если pointSample1 равен 395 градусам, а pointSample2 равен 5 градусам, нам нужно взять разницу в разрешении кодера и pointSample1, затем добавить к pointSample 2 или (PPR — pointSample1) pointSample2.

Опять же, это ДОЛЖНО давать мне количество тактов в мсек, которое затем легко преобразуется в RPM.

 #define REFRESH_RATE 1 //sets the refresh rate for tracking RPM (in mSec)

volatile float temp, counter = 0;    //This variable will increase or decrease depending on the rotation of encoder
int revsTotal = 0;
int pulseInitial = 0;
int PPR = 400;                      //Equal to the number of ticks per revolution of your encoder

unsigned long time_now = 0;         //time since program start
int pulseDifferential = 24;         //number of ticks per mSec for desired RPM
float pointSample1 = 0;             //first tick sample
float pointSample2 = 0;             //second tick sample
float pulsemSec = 0;                //the amount of ticks the encoder is reading every millisecond
float RPM = 0;                      //RPM of the motor

void setup() {

  pointSample1 = counter;

  Serial.begin (4800);

  pinMode(2, INPUT_PULLUP); //sets pin mode for pin 2

  pinMode(3, INPUT_PULLUP); //sets pin mode for pin 3
//Setting up interrupt
  //A rising pulse from encoder activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on most Arduinos.
  attachInterrupt(0, ai0, RISING);

  //B rising pulse from encoder activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on most Arduinos.
  attachInterrupt(1, ai1, RISING);
  }

  void loop() {

  // Send the value of counter
  if( counter != temp ){                        //if change is detected in the encoder, print the positional data values
  Serial.println ("Positional Data: ");
  Serial.println (counter);
  temp = counter;

    if( counter >= PPR or counter <= -PPR){ //This if statement resets the counter every time the encoder does a full revolution, protecting from reset after memory becomes filled
      counter = 0;
    }
  }
  if(millis() > (time_now   REFRESH_RATE) or millis() == 0){         //should run once every time the refresh rate is met (refresh rate = 1mSec, if statement runs once every mSec). millis() = 0; is for varibale overflow protection
    pointSample2 = counter;                       //sets pointSample2 to the encoder position, pointSample1 starts at 0. This allows the difference between the two to be taken to determine the rotation per mSec
    if(pointSample1 - pointSample2 < 0){          //conditional if / elseif statement checks the sign (positive or negative) of the ticks between samples, and makes sure that the pulses per mSec is always positive
      pulsemSec = pointSample2 - pointSample1;
    }
    else if (pointSample1 - pointSample2 > 0){
      pulsemSec = (PPR - pointSample1)   pointSample2;
    }
    RPM = (((pulsemSec / PPR) * 1000) * 60);      //pulsemSec / PPR = revs per msec; revs per msec * 1000 = revs per sec; revs per sec * 60 = RPM
    pointSample1 = pointSample2;                  //changes pointSample1 for the next cycle
    time_now = millis();                          //sets time_now to the amount of time since program start
    Serial.println ("pulsemSec: ");
    Serial.println (pulsemSec);
    Serial.println ("RPM: ");
    Serial.println (RPM);
  }
  }

  void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if(digitalRead(3)==LOW) {
  counter  ;
  }else{
  counter--;
  }
  }

  void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if(digitalRead(2)==LOW) {
  counter--;
  }else{
  counter  ;
  }
  }
  

Во время тестирования у меня был двигатель, вращающийся со скоростью около 473 оборотов в минуту, измеренный с помощью цифрового тахометра. Согласно выводам Arduino, это переведено в RPM, измеренный моим кодом как 13 350 об / мин, что намного больше. число. Я считаю, что что-то не так с измерением переменной pulsemSec, а не с тем, как она преобразуется в RPM, но я не уверен, в чем именно проблема.

Комментарии:

1. temp не инициализируется на первой итерации.

2. Вы должны вызывать millis() только один раз в каждой итерации.

3. if In else if (pointSample1 не требуется и будет маскировать, совпадают ли точечные выборки.

4. Возможно, вы теряете разрешение в своих расчетах. Попробуйте: (pulsemSec*1000*60) / PPR;

Ответ №1:

Каждый раз, когда меняются миллисекунды, вы записываете около 30 байт. 30 байт при 4800 бод — это 30/480 * 1000 мс = 62 мс. Поэтому, как только буфер заполнится, это заблокируется. Но вы предполагаете, что в ваших расчетах прошла только одна миллисекунда.

Также способ подсчета импульсов искажен:

 // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
// Check pin 3 to determine the direction

// ai[1] is activated if DigitalPin nr 3 is going from LOW to HIGH
// Check with pin 2 to determine the direction
  

итак, если у нас есть кодировка смещения, мы получаем два приращения счетчика за цикл импульсов:

 pin 2   ________********________********

pin 3   ****________********________****


                !ai0            !ai0
                    !ai1            !ai1
                counter         counter  
                    counter         counter  
  

Таким образом, вы, вероятно, увеличиваете счетчик 800 раз за оборот..