【问题标题】:Problems translating positional encoder values into RPM with Arduino使用 Arduino 将位置编码器值转换为 RPM 时出现问题
【发布时间】:2019-08-27 15:45:54
【问题描述】:

我正在使用带有 Arduino 的 400 PPR 编码器来测量编码器值。我能够让编码器读取 0-400 的正旋转值和 0 到 -400 的负旋转值,并在编码器完成完整旋转后重置为 0。我的这部分代码有效,我遇到的问题是将这些位置值转换为 RPM。

我的方法是这样的:我使用 millis() 函数来跟踪整个程序时间,并使用变量 time_now 来存储这个值。我有一个 if 语句,每次 millis() 通过 REFRESH_RATE 变得大于 time_now 时运行(在我的情况下,这被定义为 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 RPM 的速度旋转。根据 Arduino 输出,这转换为我的代码测量的 RPM 为 13,350 RPM,这个数字要高得多。我认为 pulsemSec 变量的测量不正确,而不是转换为 RPM 的方式不正确,但我不确定问题到底是什么。

【问题讨论】:

  • temp 在第一次迭代时未初始化。
  • 你应该在每个迭代中只调用一次millis()
  • else if (pointSample1 中的 if 不需要,如果点样本相同,则会屏蔽。
  • 您的计算可能会丢失分辨率。试试看:(pulsemSec*1000*60) / PPR;

标签: c++ c arduino encoder


【解决方案1】:

每毫秒变化一次,你写大约 30 个字节。 4800 波特的 30 个字节为 30/480 * 1000 ms = 62ms。因此,一旦缓冲区已满,这将阻塞。但是您假设您的计算只经过了一毫秒。

你计算脉冲的方式也有偏差:

// 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 次转一圈..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多