首页 > 解决方案 > 如何以非常高的速度 (>4500 RPM) 从旋转编码器获取数据

问题描述

设备:

Arduino ATmega2560

旋转编码器:https ://www.amazon.ca/gp/product/B08RS6M32J/ref=ppx_yo_dt_b_asin_title_o06_s01?ie=UTF8&psc=1

手动曲线跑步机(如果您以前从未见过它的样子):https ://www.youtube.com/watch?v=0oil6cmUCog&ab_channel=ResolutionFitness

背景:

我有一台手动跑步机,我想用我的 Arduino 来捕捉距离和速度数据。为此,我的方法是使用旋转编码器,将其连接到滑板轮上(附上旧图片,我现在使用的是更大的轮子,现在没有照片)这样当我在跑步机上跑步时,车轮按比例旋转。

在下面的代码中,每当我运行它时,每次轮子完全旋转时,计数器变量都会累积到大约 2000(脉冲)。车轮直径 = 6 厘米,因此,它的周长 = 18.8495559215 厘米。

这意味着我每走一厘米,就有大约 106 个脉冲。(2000 脉冲/18.8495559215 cm = ~106 脉冲/cm)。

这是代码:(我从这个网站得到它,只更改了 2 行代码,因为我的传感器不需要反向运行;跑步机只向一个方向行驶 - https://electricdiylab.com/how-to-连接光学旋转编码器与arduino/

volatile long temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
    
void setup() {
  Serial.begin (9600);

  pinMode(2, INPUT_PULLUP); // internal pullup input pin 2 
  
  pinMode(3, INPUT_PULLUP); // internalเป็น pullup input pin 3
   //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);
   
  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
  }
   
  void loop() {
  // Send the value of counter
  if( counter != temp && counter % 106 == 0 ){ // Only print something if the wheel travels in increments of 1 cm.
  Serial.println (counter);
  temp = counter;
  }
  }
   
  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++; // The original code said counter-- but my treadmill only goes one direction and the this variable starts to decrease when I reach a certain speed (around 5 kmk/h or (3.1 mph) or so). After I changed it to counter++, this issue was resolved however, the arduino serial monitor kept freezing at high speeds.


  }
  }
   
  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++; //// The original code said counter-- but my treadmill only goes one direction and the this variable starts to decrease when I reach a certain speed (around 5 kmk/h or (3.1 mph) or so). After I changed it to counter++, this issue was resolved however, the arduino serial monitor kept freezing at high speeds.
  }else{
  counter++;
  }
  }

问题

*要获得速度很容易,只是现在不在此代码中。通过使用 t1 和 t2 变量以及 Millis() 函数来实现。

当我在跑步机上行走时,我通常以大约 4 或 5 公里/小时(3.1 英里/小时)的速度行走。这工作正常。但是,问题是我希望能够以超过 30 公里/小时(18.6 英里/小时)的速度冲刺并且让代码能够支持高达 50 公里/小时(31 英里/小时)的速度。现在,如果串行监视器不定期冻结或数据不准确,我无法以超过 5 公里/小时的速度运行。

在这些速度下,我需要传感器支持以超过 4500 RPM -> 75 RPS 或(75 RPS x 2000 P/R = 150,000 脉冲/秒)移动的车轮

我完全不知道为什么会发生这个问题,以及我应该如何解决这个问题以达到我想要的速度。

发生这种情况的可能原因:

我根本不是 Arduino 的专家,我才刚刚开始了解中断之类的东西。我在 2 和 3 中有我的别针。我应该不理会它还是改变它?

如果你点击亚马逊链接,你会看到第三条橙色“Z”线,我完全不知道它的作用。我能找到的几个教程只涉及两条“A”和“B”线。也许合并“Z”线会给我指明正确的方向?

我的旋转编码器传感器使用的是 Arduino 的 5V。如果您单击亚马逊链接,您会看到它实际上支持高达 26V 的电压。我应该找到允许高达 26V 的外部电源并将其与继电器配对吗?不确定额外的电压是否对我有帮助。

我不确定为什么默认情况下,传感器将轮子的完整旋转计数为 2000 个脉冲。在 Amazon 上,您会看到它支持以下 Pulses/Revolution:

分辨率(脉冲/旋转):100、200、300、360、400、500、600、1000、1024、1200、2000、2500、3600、5000(可选)

例如,如何将我的 2000 P/R 更改为 5000 P/R?这会有帮助吗?

概括

我想使用我的 Arduino 和旋转传感器从我的手动跑步机收集速度和距离数据。在低速(最高 5 公里/小时)下,代码运行良好,但在高速下,数据非常不准确,串行监视器每隔几秒就会冻结。我希望 Arduino 支持高达 50 km/h 的速度,即大约 4500 RPM。如果我的旋转传感器解决方案不可行,我会 100% 接受其他想法,因为我只需要速度和距离数据。我会购买任何必要的新设备,但理想情况下,我想使用我现在拥有的设备。

谢谢您的帮助! 在此处输入图像描述

标签: arduinosensorsarduino-unoarduino-ide

解决方案


对于极高的速度,您必须使用位运算符和端口寄存器。

尝试使用等效引脚 CLK 和 DT 连接到 A2 和 A1 的代码。

// Rotary Encoder Inputs
#define CLK A2
#define DT A1

int counter = 0;
String currentDir ="";
unsigned char currentPairBit = 0b0; // 8 bits
unsigned char lastPairBit = 0b0; // 8 bits

void setup() {

  Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
  DDRC = 0b00000000; // Set Analog(C) encoder pins as inputs
  
}

void loop() {

  while(true) { // while cycle is faster than loop!

    // reads the analog states!
    currentPairBit = PINC >> 1 & 0b11; // Gets A2(PC2) and A1(PC1) bits on C (analog input pins) (>> 1 = Jumps pin 0)
    
    if ((lastPairBit & 0b11) != currentPairBit) {
  
      lastPairBit = lastPairBit << 2 | currentPairBit;
      
      // Bit Pairs Cyclic Sequence:
      //  1.   2.   3.   4.   5.
      //  11 | 01 | 00 | 10 | 11 for CCW
      //  11 | 10 | 00 | 01 | 11 for CW
      if (lastPairBit == 0b01001011 || lastPairBit == 0b10000111) {
    
        if (lastPairBit == 0b01001011) {
          currentDir = "CCW";
          counter--;
        } else {
          currentDir = "CW";
          counter++;    
        }
        
        Serial.print("Direction: ");
        Serial.print(currentDir);
        Serial.print(" | Counter: ");
        Serial.println(counter);
      
      }
    }
  }
}

然后检查串行监视器,看看它有多快。请注意,您应该避免delay()代码中的函数或任何其他会中断循环过多时间的函数。考虑将第二个辅助 Arduino 用于除计数之外的任何事情。

产生的串行输出: 在此处输入图像描述


推荐阅读