我正在构建一个带有两个驱动轮的简单机器人。
我想使用像这样的轮编码器来控制轮的旋转。

这是我在Arduino上尝试理解的代码我面临的问题:

 int count = 0;
void setup() {
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), upL, RISING);
  pinMode(2, INPUT);
}

void loop() {
  Serial.println(String(digitalRead(2)) + "__" + String(count));
}

void upL(){
  count++;
}
 


我注意到的是:
一次切割传感器光束时,会多次触发中断。
但是当我数字读取引脚时,只有一个变化。

我还注意到,当从HIGH变为LOW时也会触发中断。

这是我的输出示例:
0__0
0__0
0__0
0__0
...
...
0__0
0__0
0__0   <<< change from LOW to HIGH... 
1__9   <<< the interrupt must have incremented only once... 9 instead !
1__9
1__9
1__9
...
...
1__9
1__9   <<< change from HIGH to LOW. the interrupt shouldn't be triggered
0__24  <<< still... we have 15 increments
0__24
0__24
0__24
0__24
...
...
0__24
0__24   <<< same here...
1__51   <<< 26 increments
1__51
...
...
1__51  <<< same here...
0__67  <<< 16 increments
0__67
0__67


我能解释的唯一方法是,在状态改变期间,从传感器接收到的信号不是真正的方形,而是有点杂音。
如图所示:
因此,实际上,我们将会发生一次变化的许多上升...。(但是,读取模拟引脚上传感器的输出会显示从880(HIGH)到22(LOW)的直接变化)

还有其他解释吗?或解决此问题的方法?


EDIT

感谢@TobiasK我知道这被称为反弹效果。通过进一步研究,我发现了以下解决方案:
playground.arduino.cc/Main/RotaryEncoders(用于rafbuff的Ctrl + F)。 />

评论

这可能是称为“反弹”的效果。这是因为切换信号不会产生完美的边沿……而是会上下反弹。无论如何,这是电子学中的常见问题,对此问题有很多解决方案,包括电子方法(如低通滤波器)和软件方法。

通常,他们建议将例程中使用的“ Count”变量声明为Volatile。 (我想知道这是否会有所作为?)

@TobiasK对于电子方法。在传感器的输出和arduino之间增加一个电容器可以解决这个问题吗?您会建议哪种软件解决方案?在收到第一个RISING之后,我可以暂时禁用该中断。但是我们不想因为光束被切断而错过真正的上升...

尝试两边触发

这将导致更高的处理器负载,但是临时我无法想到一种复杂的基于中断的解决方案。仅基于轮询。

#1 楼

您的信号实际这样来回往复;它在微控制器中注册,因为您处于中间电压。正如@TobiasK所提到的,这称为“弹跳”。

您正试图用它来控制轮胎,所以我建议您做一些数学运算以确定“后续”信号是否可以被认为有效。

行进的距离是d = r*theta;,其中r是车轮半径,而theta是车轮旋转的角距离(以弧度为单位)。编码器每转具有一定数量的脉冲(ppr),因此,在最高速度下,您可以期望每分钟有一定数量的脉冲或每秒的脉冲。您可以使用最大车轮速度(以RPM为单位)或最大车辆速度(以[距离] /分钟为单位)来确定。

然后,取每秒最大脉冲数的倒数,以获得每个脉冲最小的秒数。在短于每个脉冲的最小秒数的时间段内检测到的任何脉冲都将无效,因此可以忽略它。

从逻辑上讲,一些伪代码可能看起来像:您的每秒脉冲数(每个脉冲减半)的值是因为您很容易在上升和下降脉冲上反弹,如上面的数据所示。

最终,您将不得不做一些事情来滤除信号中的噪声(反弹)。您可以使用电子组件(RC滤波器)以固定方式进行此操作,也可以通过软件进行此操作。我总是会尽可能推荐软件,因为如果发现您的参数沿线更改,例如升级到更快的电机等,那么它很容易更新或修改。

您甚至可以在代码的初始化部分中执行所有计算,这些计算基于您拥有的参数。然后,如果交换电动机,只需更新代码中的电动机最高速度,然后弹跳检查持续时间将自动更新。

评论


$ \ begingroup $
很棒的阅读。因此,基本上,您的想法是根据经验获得每个脉冲的最小秒数。然后忽略在少于每个脉冲最小秒数的时间内发生的任何中断?另外,我研究了我在问题编辑中给出的示例。这是一个软件解决方案。您可能希望看到它。
$ \ endgroup $
– ejalaa12
16年1月20日在20:00

$ \ begingroup $
@ ejalaa12-是的,您可以通过实验或从电机数据表中获得脉冲率。也可以设置滞后滤波器或其他低通滤波器,但是您仍然需要知道所需的截止阈值,因此所有工作都需要完成。
$ \ endgroup $
–卡盘
16年1月20日在20:19

$ \ begingroup $
我还要补充一点,即使您要使用RC滤波器,即使在设计RC滤波器时,也应该真正考虑截止阈值。有所作为!
$ \ endgroup $
–卡盘
16年1月20日在20:20

#2 楼

在研究了我在问题的EDIT上引用的代码之后。我你怎么看?您认为它可靠吗?您可以提出任何改进建议吗?

评论


$ \ begingroup $
这是一个问题,而不是答案。请修改您的原始问题,或者更好的是,提出一个新问题并链接到该问题作为参考。
$ \ endgroup $
–卡盘
16年1月21日,0:01

$ \ begingroup $
@Chuck我不确定执行此操作的方式。但我认为这是解决我的问题的答案。您是否仍建议我将其放入问题中?
$ \ endgroup $
– ejalaa12
16年1月21日在15:20

$ \ begingroup $
我会提出一个新问题,但前提是您在使用代码时遇到麻烦。目前,如果此代码有效,那么您可以接受它作为原始问题的答案。因为此站点是针对您实际遇到的问题的(而不是代码查看站点),所以如果您编写的代码没有问题,那么可能不会收到很多反馈,而您会遇到问题容易被关闭。
$ \ endgroup $
–卡盘
16年1月21日在15:39