arduino - 如何以非常高的速度 (>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% 接受其他想法,因为我只需要速度和距离数据。我会购买任何必要的新设备,但理想情况下,我想使用我现在拥有的设备。
解决方案
对于极高的速度,您必须使用位运算符和端口寄存器。
尝试使用等效引脚 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 用于除计数之外的任何事情。
推荐阅读
- layout - 在 VScode 中,如何拆分面板以使终端和编辑器彼此相邻
- apache-zookeeper - Apache Curator ZooKeeper 单元测试给出错误
- python - 通过检查连续行中的值来循环数据框组
- java - Java - 对数组中的单词对象进行排序
- python - 你如何减去日期时间对象?
- javascript - 使用下拉菜单动态更新条形图
- r - 在 R 中放大地图
- ruby - Redpotion 中的 rake 问题 - 在 OSX Catalina 10.15.4 上推广
- javascript - 如何重复调用回调函数?
- javascript - 为什么我的命名捕获组不起作用?