C++ 使用Arduino将位置编码器值转换为RPM时出现问题

C++ 使用Arduino将位置编码器值转换为RPM时出现问题,c++,c,arduino,encoder,C++,C,Arduino,Encoder,我使用一个400 PPR编码器和一个Arduino来测量编码器值。我能够让编码器读取值0-400(正旋转)和0到-400(负旋转),并在编码器完全旋转后重置为0。这部分代码是有效的,我遇到的问题是将这些位置值转换为RPM 我的方法是这样的:我使用millis()函数来跟踪整个程序时间,现在使用一个可变的time_来存储这个值。我有一个if语句,每当millis()以刷新率(在我的例子中,它定义为1毫秒)大于time_now时,它就会运行一次,因此每1毫秒运行一次 我的下一个方法是每毫秒采集两个样

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

我的方法是这样的:我使用millis()函数来跟踪整个程序时间,现在使用一个可变的time_来存储这个值。我有一个if语句,每当millis()以刷新率(在我的例子中,它定义为1毫秒)大于time_now时,它就会运行一次,因此每1毫秒运行一次

我的下一个方法是每毫秒采集两个样本。pointSample1和pointSample2之间的差异应该是编码器在1毫秒内移动的滴答数。这变得有点复杂,因为它本质上是一个400度的圆,所以例如,如果pointSample1是395度,pointSample2读取5度,我们需要获取编码器分辨率和pointSample1的差值,然后添加到pointSample2或(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++;
  }
  }
#定义刷新率1//设置跟踪RPM的刷新率(毫秒)
挥发性浮子温度,计数器=0//该变量将根据编码器的旋转增加或减少
int revsTotal=0;
int脉冲初始值=0;
int PPR=400//等于编码器每转的滴答数
无符号长时间_now=0//程序启动后的时间
int脉冲微分=24//所需RPM每毫秒的滴答数
浮点采样1=0//首个蜱虫样本
浮点采样2=0//第二个蜱虫样本
浮动脉冲秒=0//编码器每毫秒读取的滴答数
浮动转速=0//电机转速
无效设置(){
pointSample1=计数器;
Serial.begin(4800);
pinMode(2,输入_上拉);//设置插脚2的插脚模式
pinMode(3,输入_上拉);//设置插脚3的插脚模式
//设置中断
//来自编码器的上升脉冲激活了ai0()。在大多数Arduinos上,AttachInterrupt 0是数字引脚nr 2。
附加中断(0,ai0,上升);
//B来自编码器的上升脉冲激活了ai1()。在大多数Arduinos上,AttachInterrupt 1是数字引脚nr 3。
附加中断(1,ai1,上升);
}
void循环(){
//发送计数器的值
如果(计数器!=temp){//如果在编码器中检测到更改,则打印位置数据值
Serial.println(“位置数据:”);
Serial.println(计数器);
温度=计数器;
if(counter>=PPR或counter(time\u now+REFRESH\u RATE)或millis()==0){//应在每次满足刷新率时运行一次(REFRESH RATE=1mSec,if语句每毫秒运行一次)。millis()=0;用于变量溢出保护
pointSample2=counter;//将pointSample2设置为编码器位置,pointSample1从0开始。这允许取两者之间的差值来确定每毫秒的旋转
if(pointSample1-pointSample2<0){//conditional if/elseif语句检查样本之间的刻度符号(正或负),并确保每毫秒的脉冲始终为正
脉冲秒=点采样2-点采样1;
}
else if(点采样1-点采样2>0){
脉冲秒=(PPR-点采样1)+点采样2;
}
RPM=((脉冲秒/PPR)*1000)*60);//脉冲秒/PPR=每秒转速;每秒转速*1000=每秒转速;每秒转速*60=RPM
pointSample1=pointSample2;//为下一个循环更改pointSample1
time_now=millis();//将time_now设置为程序启动后的时间量
Serial.println(“脉冲秒:”);
Serial.println(脉冲秒);
Serial.println(“RPM:”);
Serial.println(RPM);
}
}
void ai0(){
//如果DigitalPin nr 2从低变高,则激活ai0
//检查销3以确定方向
如果(数字读取(3)=低){
计数器++;
}否则{
计数器--;
}
}
无效ai1(){
//如果DigitalPin nr 3从低变高,则激活ai0
//用销2检查以确定方向
如果(数字读取(2)=低){
计数器--;
}否则{
计数器++;
}
}

在测试过程中,我用数字转速表测量了一个电机在473转/分左右旋转。根据Arduino输出,这转化为我的代码测得的13350转/分,一个更高的数字。我相信pulsemSec变量的测量不正确,转换为转/分的方式也不正确,但我不是苏这就是问题所在。

每次毫秒变化时,您都会写入大约30个字节。4800波特时的30个字节是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次递增。

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