Pyrrhus 发表于 2015-1-13 16:26:11

Arduino红外遥控IRremote扩展库的深入研究----让接受更稳定

本帖最后由 弘毅 于 2017-4-23 14:05 编辑

    我从GitHub下载了最新的IRremote扩展库:https://github.com/shirriff/Arduino-IRremote
拿了一个机顶盒的遥控器测试了一下,发现解码非常不稳定,时灵时不灵,换了一个遥控器还是一样,
只能加入调试代码,本来只想调整一下参数,让解码更稳定一些,后来发现代码里有一段逻辑有些问题,
IRremote.cpp代码如下:
int MATCH_MARK(int measured_ticks, int desired_us) {
Serial.print("Testing mark ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
}

int MATCH_SPACE(int measured_ticks, int desired_us) {
Serial.print("Testing space ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
}

Pyrrhus 发表于 2015-1-13 16:33:39

本帖最后由 弘毅 于 2017-4-23 14:06 编辑

参考IRremoteInt.h的代码:
#define TOLERANCE 25// percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)

#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)

#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))

以及IRremote.h的代码:
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100

Pyrrhus 发表于 2015-1-13 17:17:13

本帖最后由 弘毅 于 2017-4-23 14:09 编辑

其中,
MARK_EXCESS是用来补正程序运行时的延迟,默认是100us;
TOLERANCE是容错率,默认25,表示可以允许25%的误差;
TICKS_LOW和TICKS_HIGH用来算容错上下限。

再联系IRremote.cpp我贴出来的53行和67行,
把MARK_EXCESS的补正放到TICKS_LOW和TICKS_HIGH里,事实上就把补正放大了,
本来是100us的,现在就是125us。

修改也比较简单,把53行和67行的MARK_EXCESS的拿出来:
return measured_ticks - MARK_EXCESS/USECPERTICK >= TICKS_LOW(desired_us) && measured_ticks - MARK_EXCESS/USECPERTICK <= TICKS_HIGH(desired_us);

return measured_ticks + MARK_EXCESS/USECPERTICK >= TICKS_LOW(desired_us) && measured_ticks + MARK_EXCESS/USECPERTICK <= TICKS_HIGH(desired_us);


另外,MARK_EXCESS默认的100us有点大,把它设成50us可能更好:
#define MARK_EXCESS 50


还有就是TOLERANCE,一般的红外协议占空比是1/3,也就是说到300%的误差才会串码,
如果误码多的话,把TOLERANCE调大也是一个方法。
#define TOLERANCE 50// percent tolerance in measurements

Pyrrhus 发表于 2015-1-13 17:19:44

通过上面的修改,IRremote库的解码会稳定很多。

Pyrrhus 发表于 2015-1-14 12:14:17

本帖最后由 弘毅 于 2017-4-23 14:04 编辑

还是漏了一段,上面的修改只是在DEBUG模式下,正常模式下的修改在下面:
int MATCH(int measured, int desired) {return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);}
int MATCH_MARK(int measured_ticks, int desired_us) {return MATCH((measured_ticks - MARK_EXCESS/USECPERTICK), desired_us);}
int MATCH_SPACE(int measured_ticks, int desired_us) {return MATCH((measured_ticks + MARK_EXCESS/USECPERTICK), desired_us);}

yuanzhi 发表于 2015-1-14 17:51:51

终于来明白人了,谢谢分享,必须得顶!

stpanzj 发表于 2015-6-12 11:30:18

本帖最后由 stpanzj 于 2015-6-12 11:41 编辑

我认为,这里加入MARK_EXCESS的意思是在MARK的时候,值经常是偏大的,而SPACE的时候测到的值经常是偏小的。
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
因此测MARK时下限应该不变,变的是上限;测SPACE时变下限,上限不变。所以我觉得应该如下修改,取消MATCH,直接在MATCH_MARK/MATCH_SPACE中改公式,更好理解:

int MATCH_MARK(int measured_ticks, int desired_us) {return measured_ticks >= TICKS_LOW(desired_us) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);}
int MATCH_SPACE(int measured_ticks, int desired_us) {return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us);}

也就是删70,改71、72行。晚上回去试一试,看是否实际结果会更好些,我也遇到decode的结果不稳定。

还有
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK)+1)
不知道为何要加1。不加1可以理解,是(1+比例)*原始值,也就是加上上限后的值。加1就不知道为啥了,加上上限后再大1,太小气了。

coolhead 发表于 2015-12-8 13:41:22

关于空调解码的问题,国外的analys大神给出了一个解码方案,同时解码的长度达到800位,上面两位朋友可以参考一下
analyse大声空调长解码解决方案
网页链接http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/
附上代码/*
Author: AnalysIR
Revision: 1.0

This code is provided to overcome an issue with Arduino IR libraries
It allows you to capture raw timings for signals longer than 255 marks & spaces.
Typical use case is for long Air conditioner signals.

You can use the output to plug back into IRremote, to resend the signal.

This Software was written by AnalysIR.

Usage: Free to use, subject to conditions posted on blog below.
Please credit AnalysIR and provide a link to our website/blog, where possible.

Copyright AnalysIR 2014

Please refer to the blog posting for conditions associated with use.
http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/

Connections:
IR Receiver      Arduino
V+          ->+5v
GND          ->GND
Signal Out   ->Digital Pin 2
(If using a 3V Arduino, you may connect V+ to +3V)
*/

#define LEDPIN 13
//you may increase this value on Arduinos with greater than 2k SRAM
#define maxLen 800

volatileunsigned int irBuffer; //stores timings - volatile because changed by ISR
volatile unsigned int x = 0; //Pointer thru irBuffer - volatile because changed by ISR

void setup() {
Serial.begin(9600); //change BAUD rate as required
attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//set up ISR for receiving IR signal
}

void loop() {
// put your main code here, to run repeatedly:

//Serial.println(F("Press the button on the remote now - once only"));
delay(5000); // pause 5 secs
if (x) { //if a signal is captured
    digitalWrite(LEDPIN, HIGH);//visual indicator that signal received
    Serial.println();
    Serial.print(F("Raw: (")); //dump raw header format - for library
    Serial.print((x - 1));
    Serial.print(F(") "));
    detachInterrupt(0);//stop interrupts & capture until finshed here
    for (int i = 1; i < x; i++) { //now dump the times
      //if (!(i & 0x1)) Serial.print(F("-"));
      Serial.print(irBuffer - irBuffer);
      Serial.print(F(","));
    }
    x = 0;
    Serial.println();
    Serial.println();
    digitalWrite(LEDPIN, LOW);//end of visual indicator, for this time
    attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//re-enable ISR for receiving IR signal
}

}

void rxIR_Interrupt_Handler() {
if (x > maxLen) return; //ignore if irBuffer is already full
irBuffer = micros(); //just continually record the time-stamp of signal transitions

}但这样的话,解码的还是会有些不稳定,希望可以一起探讨一下,这种方案 就是直接利用外部中断,感知红外接收管电平变化

太行摄狼 发表于 2017-4-22 22:37:27

看了半天也不明白,软件不行啊,楼主能发一个改好的文件吗,我也在为解码乱困惑

mondaywoo 发表于 2017-4-22 23:57:26

初学者学习
页: [1]
查看完整版本: Arduino红外遥控IRremote扩展库的深入研究----让接受更稳定