2011年4月1日 星期五

紅外線物體偵測 (3)

IRremote 函式庫也可以做紅外線物體偵測,方法是用 IRremote 讓紅外線發射器 (IR LED) 產生 38 kHz 的脈波,然後用一般 38 kHz 的紅外線接收器來偵測訊號。

註: 在「紅外線物體偵測(1)」(反射型)和「紅外線物體偵測(2)」(遮光型)這兩篇的範例程式中,紅外線發射器(IR LED) 38 kHz 的脈波是利用 tone() 函式產生的。

線路的接法還是一樣,如下圖,把紅外線發射器串接一顆 100 歐姆的電阻接到 pin 3,然後把紅外線接收器接到 pin 2:

image
程式

底下這支程式(IRRemoteObjDetect.pde)示範用 IRremote 函式庫做紅外線物體偵測:

要產生 38 kHz 的脈波,只要呼叫 irsend.enableIROut(38); 設定 PWM 的頻率,接著再呼叫 irsend.mark(0); 打開輸出讓 IR LED 開始輸出訊號,這樣就可以了。

就看你的發射器與接收器的接法為何,如果是反射型的,在偵測到物體時 pin 13 上的指示燈會閃爍,如果是遮光型的,那麼 pin 13 上的指示燈平常會一直閃爍,在偵測到物體時會熄滅。

延伸閱讀

16 則留言:

  1. IRsend這個函式除了enableIROut和mark之外, 還
    有哪些方法可以使用?

    回覆刪除
  2. IRsend 除了 sendXXX() 這系列方法跟 enableIROut, mark 外, 還有一個 space() 方法。space() 的作用正好與 mark() 相反。

    這是 IRsend 的定義 (可以在 IRRemote.h 裏找到):

    class IRsend
    {
    public:
    IRsend() {}
    void sendNEC(unsigned long data, int nbits);
    void sendSony(unsigned long data, int nbits);
    void sendRaw(unsigned int buf[], int len, int hz);
    void sendRC5(unsigned long data, int nbits);
    void sendRC6(unsigned long data, int nbits);
    void sendDISH(unsigned long data, int nbits);
    void sendSharp(unsigned long data, int nbits);
    // private:
    void enableIROut(int khz);
    VIRTUAL void mark(int usec);
    VIRTUAL void space(int usec);
    }

    回覆刪除
  3. 如果我要接4組這樣的反射型物體偵測,
    電路和程式該如何做?

    回覆刪除
  4. 你要接 4 組?
    我不確定 IRRemote 能不能同時用多組紅外線接收器
    不過你可以試試看,紅外線接收器不限定接哪支腳位
    所以你只要照這篇的接線圖增加幾顆紅外線接收器就可以了
    至於程式的話,把它當 digital input 來看用 digitalRead() 來讀訊號就行
    只是要注意訊號會反,0 代表有物體,1 代表沒有物體

    回覆刪除
  5. 是不是無法同時發射2組以上的脈波? 底下的程式只有第1組可以正常動作:
    /*
    * irObjectDetection.pde: 紅外線物體偵測
    */
    const int irRec1 = 2; // 紅外線接收器
    const int irLed1 = 3; // 紅外線發射器
    const int ledPin1 = 12; // 紅外線指示燈
    const int irRec2 = 4; // 紅外線接收器
    const int irLed2 = 5; // 紅外線發射器
    const int ledPin2 = 13; // 紅外線指示燈
    const unsigned int frequency = 38000; // 發射頻率(單位: Hz)

    void setup() {
    pinMode(irRec1, INPUT); // 把 irReceiver 接腳設置為 INPUT
    pinMode(irLed1, OUTPUT); // 把 irLed 接腳設置為 INPUT
    pinMode(ledPin1, OUTPUT); // 把 ledPin 設置為 OUTPUT
    pinMode(irRec2, INPUT); // 把 irReceiver 接腳設置為 INPUT
    pinMode(irLed2, OUTPUT); // 把 irLed 接腳設置為 INPUT
    pinMode(ledPin2, OUTPUT); // 把 ledPin 設置為 OUTPUT
    tone(irLed1, frequency); // 產生指定頻率的脈波 (Pulses)
    tone(irLed2, frequency); // 產生指定頻率的脈波 (Pulses)

    }

    // 讓指示燈閃爍幾下
    void blinkLED(int ledPin) {
    for (int i=1; i<= 3; i++) {
    digitalWrite(ledPin, HIGH); // 打開指示燈
    delay(100);
    digitalWrite(ledPin, LOW); // 關掉指示燈
    delay(100);
    }
    }

    void loop() {
    int ir1 = digitalRead(irRec1); // 讀取 irReceiver 的狀態
    if (ir1 == 0) blinkLED(ledPin1); // 讓指示燈閃爍幾下
    int ir2 = digitalRead(irRec2); // 讀取 irReceiver 的狀態
    if (ir2 == 0) blinkLED(ledPin2); // 讓指示燈閃爍幾下
    }

    回覆刪除
  6. arduino.cc 討論區有人在討論能不能用 tone() 多個聲音:
    http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1266588204

    scswift 分享了他的經驗 "I tried using tone() today, with two piezos hooked up to different pins, and I found that when you call tone() to play a tone on one pin, you must call noTone() for that pin before calling tone() on another pin... even if the sound on the first pin has stopped playing.
    "

    所以我想可能沒辦法用 tone() 同時播放聲音或送脈波。只能一個接一個送,而且送完一個脈波後,還要用 noTone() 結束脈波的傳送。

    回覆刪除
  7. 呵~~視頻是做一隻會唱歌的晨鳥.
    我的第一個作品是只要敲鍵盤任意鍵Arduino就會發出一個音符,所以當使用者在打鍵盤時樂曲就會流洩出來,我想做的東西就是一個"陪伴電腦使用者"的裝置.
    剛開始還蠻新鮮的, 但那種合成的聲音是很死硬的, 聽久就膩了, 所以我後來就改成透過馬達驅動實體音樂盒, 這樣的聲音效果好多了.

    回覆刪除
  8. 既然Arduino無法同時使用2個tone()發出38KHz脈波或發出複音, 那麼我想應該有下列兩種方法解決這個問題:
    1.模仿cpu分時多工的觀念, 透過適時地切換tone()與noTone()來達成.
    2.用硬體方式解決, 利用IC555發出38KHz脈波或音頻訊號.

    回覆刪除
  9. 底下是2組紅外線偵測物體的程式碼:
    /*
    * irObjectDetection.pde: 紅外線物體偵測
    */
    const int irRec1 = 2; // 紅外線接收器
    const int irLed1 = 3; // 紅外線發射器
    const int ledPin1 = 12; // 紅外線指示燈
    const int irRec2 = 4; // 紅外線接收器
    const int irLed2 = 5; // 紅外線發射器
    const int ledPin2 = 13; // 紅外線指示燈
    const unsigned int frequency = 38000; // 發射頻率(單位: Hz)

    void setup() {
    pinMode(irRec1, INPUT); // 把 irReceiver 接腳設置為 INPUT
    pinMode(irLed1, OUTPUT); // 把 irLed 接腳設置為 INPUT
    pinMode(ledPin1, OUTPUT); // 把 ledPin 設置為 OUTPUT
    pinMode(irRec2, INPUT); // 把 irReceiver 接腳設置為 INPUT
    pinMode(irLed2, OUTPUT); // 把 irLed 接腳設置為 INPUT
    pinMode(ledPin2, OUTPUT); // 把 ledPin 設置為 OUTPUT
    }

    // 讓指示燈閃爍
    void blinkLED(int ledPin) {
    digitalWrite(ledPin, HIGH); // 打開指示燈
    delay(100);
    digitalWrite(ledPin, LOW); // 關掉指示燈
    delay(100);
    }

    void loop() {
    tone(irLed1, frequency); // 產生指定頻率的脈波 (Pulses)
    delay(100);
    int ir1 = digitalRead(irRec1); // 讀取 irReceiver 的狀態
    if (ir1 == 0) blinkLED(ledPin1); // 讓指示燈閃爍幾下
    noTone(irLed1);
    //
    tone(irLed2, frequency); // 產生指定頻率的脈波 (Pulses)
    delay(100);
    int ir2 = digitalRead(irRec2); // 讀取 irReceiver 的狀態
    if (ir2 == 0) blinkLED(ledPin2); // 讓指示燈閃爍幾下
    noTone(irLed2);
    }
    這種方式有缺點, 所以看來似乎應該用硬體方式解決會比較好.

    回覆刪除
  10. Arduino除了tone()這個函數可以發出38KHz脈波之外, 還有其它函數可以做到嗎?

    回覆刪除
  11. Arduino core library 裏只有 tone() 這個函數可以產生各種頻率的脈波。如果要發複音,可能利用 timer 的 pwm 功能,可能要研究一下 tone() 的程式碼,然後看看有沒有多餘的 timer 可供使用。

    回覆刪除
  12. 簡易播複音的方法:
    Simple Polyphonic Synth - Just WIth Arduino
    http://little-scale.blogspot.com/2008/02/simple-polyphonic-synth-with-just.html

    回覆刪除
  13. 最近看到兩位的討論使我受益良多,我試實作出發射兩組38kHz使用切換tone()與noTone(),做出的是2個遮光型的紅外線感測器,程式部分修改 芭蕉葉上聽雨聲前輩所說之有缺點的方式。
    /*
    * irObjectDetection.pde: 紅外線物體偵測
    */
    const int irRec1 = 2; // 紅外線接收器
    const int irLed1 = 3; // 紅外線發射器
    const int ledPin1 = 12; // 紅外線指示燈
    const int irRec2 = 4; // 紅外線接收器
    const int irLed2 = 5; // 紅外線發射器
    const int ledPin2 = 13; // 紅外線指示燈
    const unsigned int frequency = 38000; // 發射頻率(單位: Hz)

    void setup() {
    pinMode(irRec1, INPUT); // 把 irReceiver 接腳設置為 INPUT
    pinMode(irLed1, OUTPUT); // 把 irLed 接腳設置為 INPUT
    pinMode(ledPin1, OUTPUT); // 把 ledPin 設置為 OUTPUT
    pinMode(irRec2, INPUT); // 把 irReceiver 接腳設置為 INPUT
    pinMode(irLed2, OUTPUT); // 把 irLed 接腳設置為 INPUT
    pinMode(ledPin2, OUTPUT); // 把 ledPin 設置為 OUTPUT
    }

    // 讓指示燈閃爍
    void blinkLED(int ledPin) {
    digitalWrite(ledPin, HIGH); // 打開指示燈
    delay(100);
    digitalWrite(ledPin, LOW); // 關掉指示燈
    delay(100);
    }

    void loop() {
    tone(irLed1, frequency); // 產生指定頻率的脈波 (Pulses)
    delay(100);
    int ir1 = digitalRead(irRec1); // 讀取 irReceiver 的狀態
    if (ir1 == 1) blinkLED(ledPin1); // 讓指示燈閃爍幾下
    noTone(irLed1);
    //
    tone(irLed2, frequency); // 產生指定頻率的脈波 (Pulses)
    delay(100);
    int ir2 = digitalRead(irRec2); // 讀取 irReceiver 的狀態
    if (ir2 == 1) blinkLED(ledPin2); // 讓指示燈閃爍幾下
    noTone(irLed2);
    }

    修改完似乎沒有什麼問題出現@@
    依照這個程式來走的話是,irRec2被遮住的話ledPin2閃爍,irRec1被遮住的畫ledPin1閃爍,兩個一起遮住,兩個一起閃爍。
    我想如果想要使用兩個tone()的話,使用tone()與noTone()這個方法可行。

    回覆刪除
  14. LCW恭喜你實做成功.

    請問你的紅外線發射與接收, 有效距離最遠是幾公尺?

    回覆刪除
  15. 芭蕉葉上聽雨聲你好

    我只是在麵包板上把電路實作出來...

    所以發射端與接收端的距離,僅僅只有14cm而已@@

    有效最遠距離的話,因為手邊沒有兩塊麵包板所以沒辦法實測...

    回覆刪除
  16. LCW 恭禧你實作成功
    歡迎兩位常來啊!^o^

    回覆刪除

注意:只有此網誌的成員可以留言。