2011年3月15日 星期二

Arduino 筆記 – Lab20 用紅外線動作感測器 (PIR Motion Sensor) 控制 LED 的開關

實驗目的

練習使用紅外線動作感測器 (PIR Motion Sensor),利用紅外線動作感測器來控制 LED 的開關。

紅外線動作感測器

image
▲ 紅外線動作感測器 (PIR Motion Sensor)

紅外線動作感測器 (PIR Motion Sensor) 或稱人體紅外線感測器,是一種可以偵測物體移動的電子裝置。生活中很多東西都會發射紅外線,例如燈泡、蠟燭、中央空調等,其實人體也會發射紅外線,紅外線動作感測器的原理,便是利用人體發射出來的紅外線的變化,來感應物體的移動。

紅外線感測器有分主動式和被動式兩種。主動式的紅外線感測器,感應器本身會發射紅外線光束,當紅外線光束被物體擋住後,紅外線光束會反射,利用這個紅外線反射原理可以做很多應用,例如廁所的自動沖水小便斗或感應式水龍頭,它們用的就是主動式紅外線感測器。紅外線動作感測器 (PIR Motion Sensor) 是屬於被動式的紅外線裝置,感應器本身不會發射紅外線光束。PIR 是 Passive Infrared Sensor (被動式紅外線感測器) 的縮寫。

紅外線動作感測器一般用在防盜系統上,例如有人入侵屋內便響警報的紅外警報器,或是自動照明裝置,例如玄關、走廊、樓梯間或車庫門口不常有人走動,將紅外線感應器和燈具裝在這些地方,只要有人就自動開燈照明,人離開後就自動關燈省電。

紅外線動作感測器腳位表

一般來說,紅外線動作感測器只有三支接腳,這三支接腳的功能如下表:

腳位名稱 功能說明
GND (-) 接到接地
Power (+ or V+) 接到 +5V 電源
OUT 輸出訊號

在感測到物體移動時,紅外線動作感測器就會在 OUT 腳上輸出一個訊號,利用這個訊號就可以知道感測器附近是否有人。另外,大部份紅外線動作感測器都有一個旋轉鈕,可讓使用者調整訊號輸出的延遲時間,這個設計非常貼心,因為利用延遲時間我們可以延遲關燈的時間,避免燈具開關太過頻繁。

材料
  • 麵包板 x 1
  • Arduino 主板 x 1
  • 紅外線動作感測器 (PIR Motion Sensor) x 1
  • 單心線 x N
接線
  • 把 LED 接到 Arduino 板子上,LED 長腳 (陽極) 接到 pin13,短腳 (陰極) 接到 GND
  • 把紅外線動作感測器 GND 腳位接到 GND,V+ 腳位接到 +5V,然後 OUT 腳位接到數位輸入(Digital pins) pin 2

image

接線圖中的 LED 沒有串接電阻,這是因為 Arduino 的輸出電流很小不會燒壞 LED,所以才敢這麼做,少接一顆電阻是為了簡化。一般來說,LED 串接一顆電阻 (220 歐姆) 是個好主意。

程式碼

底下是用紅外線動作感測器來控制 LED 開關的程式 (PIRSensor.pde):

如你所見,讀取紅外線動作感測器的訊號,幾乎就像是在讀取按鍵訊號一樣,程式邏輯超乎想像的簡單,不需要多解釋。

動動腦
  1. 請加個蜂鳴器或喇叭製作一個紅外線警報器,在偵測到有人進入屋內時便響警報。
  2. 參考「使用 Firmata 協定連接 Processing 與 Arduino」一文,試撰寫一支 Processing 程式觀察紅外線動作感測器的狀態,當發現有人入侵屋內時,便自動以 Skype 撥電話或送簡訊到你的手機上。
延伸閱讀

25 意見:

jacky841102 提到...

不好意思,我想請教一個問題
我照著你的程式灌到我的arduino
照理說pin2應該是高電位時LED才會亮
但是當我都沒接電路時,只接LED卻會亮耶
是怎麼一會事? 是我的板子的問題嗎?

Cooper Maa 提到...

Hi, 你是說 pin2 還沒有接 PIR Sensor 嗎? 這樣的話 pin2 是浮接的狀態,很容易受到環境的電子干擾喔。

jacky841102 提到...

是喔,環境中的電子影響那麼大?
請問是輸入多少電壓,才會判斷為High

Cooper Maa 提到...

以我對硬體粗淺的了解,浮接腳位,又稱高阻抗腳位,它的狀態是不穩定的,只要有一丁點電流就會影響腳位的狀態。也許你可以暫時打開 pin 2 的提升電阻避免這個問題。請參考我前幾天整理的「Arduino 的提升電阻」一文。

芭蕉葉上聽雨聲 提到...

如何能讓人在時, PIR的訊號一直是HIGH, 而非延遲時間到了之後先成LOW再重新偵測?
如何能讓人離開時訊號馬上是LOW?

Cooper Maa 提到...

要馬上 LOW? PIR 的 Time delay 一般是 5 秒到 200 秒或 5 分鐘,也許可以試試轉到 5 秒鐘。
第一個的話,有可能是人沒在室內都沒動造成 PIR 偵測不到的關係,這點的話可以試著調 sensitive

Nagi 提到...

您好
請問將紅外線感應和蜂鳴器2個例子結合時,
如何讓蜂鳴器和LED同調?

我將蜂鳴器的例子改寫後放入紅外線感應的例子中,
LED運作OK,但是蜂鳴器就算將delay拿掉還是會一直唱歌;根本不受紅外線影響

Cooper Maa 提到...

可以把你的程式碼貼上來嗎?

Nagi 提到...

這個是我直接將改寫過的蜂鳴器成是貼入紅外線中,再改掉delay;蜂鳴器的音樂還是會不受紅外線影響,而且LED好像還會跟蜂鳴器同步。
---
/*
PIR("Passive Infrared Sensor") Motion Sensor,
紅外線動作感測器, 或稱人體紅外線感測器
*/

const int PIRSensor = 2; // 紅外線動作感測器連接的腳位
const int ledPin = 13; // LED 腳位
#include "pitches.h"
int melody[] = {
NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4};
int duration = 500;

int sensorValue = 0; // 紅外線動作感測器訊號變數

void setup() {
pinMode(PIRSensor, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop(){
// 讀取 PIR Sensor 的狀態
sensorValue = digitalRead(PIRSensor);

// 判斷 PIR Sensor 的狀態
if (sensorValue == HIGH) {
for (int thisNote = 0; thisNote < 8; thisNote++) {
// 在 pin8 上輸出聲音,每個音階響 0.5 秒
tone(8, melody[thisNote], duration);

// 間隔一段時間後再播放下一個音階
delay(500);
}

// 兩秒後重新播放
delay(0);

digitalWrite(ledPin, HIGH); // 有人,開燈
}
else {
digitalWrite(ledPin, LOW); // 沒人,關燈
}
}

Nagi 提到...

然後我又嘗試改成下面這樣,
程式碼似乎沒有錯誤;但無法上傳,會一直顯示Uploading

Arduion很有趣,可是程式碼寫不出來時真的很沮喪...
---
/*
PIR("Passive Infrared Sensor") Motion Sensor,
紅外線動作感測器, 或稱人體紅外線感測器
*/

const int PIRSensor = 2; // 紅外線動作感測器連接的腳位
const int ledPin = 13; // LED 腳位
const int BUZZER = 8; // BUZZER 腳位
#include "pitches.h"
int melody[] = {
NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4};
int duration = 500;

int sensorValue = 0; // 紅外線動作感測器訊號變數

void setup() {
pinMode(PIRSensor, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(BUZZER, OUTPUT);
for (int thisNote = 0; thisNote < 8; thisNote++) {
// 在 pin8 上輸出聲音,每個音階響 0.5 秒
tone(8, melody[thisNote], duration);

// 間隔一段時間後再播放下一個音階
delay(500);
}

// 兩秒後重新播放
delay(0);
}

void loop(){
// 讀取 PIR Sensor 的狀態
sensorValue = digitalRead(PIRSensor);

// 判斷 PIR Sensor 的狀態
if (sensorValue == HIGH) {

digitalWrite(ledPin, HIGH); // 有人,開燈
digitalWrite(BUZZER,HIGH);
}
else {
digitalWrite(ledPin, LOW); // 沒人,關燈
digitalWrite(BUZZER,LOW);
}
}

Cooper Maa 提到...

程式這樣寫的話,只要 PIR 一偵測到有物體,蜂鳴器就會唱完一次才會停喔

你不能用 for 迴圈跟 delay 播放聲音, 可能要用 BlinkWithoutDelay (http://arduino.cc/en/Tutorial/BlinkWithoutDelay) 的方法播放聲音

另外,當 PIR 為 false 時,建議用 noTone() 關閉蜂鳴器

Nagi 提到...

有點不是很理解,
嘗試寫了,
不知道是不是這樣?
---
const int PIRSensor = 2; // 紅外線動作感測器連接的腳位
const int ledPin = 13; // LED 腳位
const int BUZZER = 8; // BUZZER 腳位
#include "pitches.h"
int melody[] = {
NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4,NOTE_E5, NOTE_C4};
int duration = 500;

int sensorValue = 0; // 紅外線動作感測器訊號變數
int ledpin = HIGH

void setup() {
pinMode(PIRSensor, INPUT);
pinMode(ledPin, OUTPUT);
pinMode(BUZZER, OUTPUT);

void loop(){
// 讀取 PIR Sensor 的狀態
sensorValue = digitalRead(PIRSensor);

// 判斷 PIR Sensor 的狀態
if (sensorValue == HIGH) {

digitalWrite(ledPin, HIGH); // 有人,開燈

}
else {
digitalWrite(ledPin, LOW); // 沒人,關燈

}

if(ledPin==HIGH){
tone(8, melody[thisNote], duration);
{
else{
notone(8);
}

}

Cooper Maa 提到...

程式裏沒有 delay
這樣可能會沒有聲音喔

我在想也許要改用 attachInterrupt 來控制比較好:
http://coopermaa2nd.blogspot.tw/2011/04/attachinterrupt.html

samhuang 提到...

請問一下要怎麼改變他處發後的時間??
EX.HIGH時LED亮一秒
在城市裡面加DELAY好像沒有用
不管怎麼打他都會亮一段固定時間(14秒)後自己關掉???
這要怎麼解決

Cooper Maa 提到...

PIR 觸發的訊號會持續一段時間
不過 LED 是用程式控制的,可以自行決定要亮多久的時間,你可以在收到 PIR 訊號後讓 LED 亮一秒然後就關掉,只要在固定時間內不要再把它打開就行了

samhuang 提到...

謝謝您的回答
有辦法讓他像 按鈕一樣 案(偵測到人)就ON 不按(沒偵測到人)就OFF 而不適每次ON後都一段時間後才會OFF

Cooper Maa 提到...

PIR Sensor 的特性是,偵測到動作時 Trigger 訊號會持續幾秒鐘,偵測不到沒動作時 Trigger 訊號也會持續幾秒鐘,這部份不是 Arduino 可以控制的喔

samhuang 提到...

喔喔了解~~
我還是用測距紅外線好了
謝謝您的回覆:)

另外我想請教版大關於MP3 SHIELD
http://goods.ruten.com.tw/item/show?21103035876602
站內有教學嗎??
我沒找到

Cooper Maa 提到...

不客氣

沒有喔,我沒有玩過 MP3 Shield,所以沒寫筆記

samhuang 提到...

版大有個問題想請教您

我要做一個裝置

有人到時步進馬達會轉

媒人時他部會轉

我希望感測到人以後會轉五秒

可是加入delay(5000);後

感測到以後馬達根本部會動

為什麼會這樣??? >_<

(如果把delay拿掉的話一切正常,人來他就轉,人走他就停)

#include

const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution
// for your motor


// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8,9,10,11);

int stepCount = 0; // number of steps the motor has taken


void setup() {
// nothing to do inside the setup
Serial.begin(9600);
pinMode(led,OUTPUT);
}

void loop() {
// read the sensor value:
int sensorReading = analogRead(A0);
Serial.println(sensorReading);
// map it to a range from 0 to 100:
//int motorSpeed = map(sensorReading, 0, 1023, 0, 100);
// set the motor speed:
if (sensorReading > 400) {

myStepper.setSpeed(15);
myStepper.step(stepsPerRevolution/100);
delay(5000);

// step 1/100 of a revolution:

}
}

Cooper Maa 提到...

delay() 是 blocking operation,你一呼叫它,CPU 就卡在那裏不動,所以馬達不會動是當然的啦

解決方法是盡量不要用 delay() function,你可以參考一下這篇:
http://coopermaa2nd.blogspot.tw/2011/04/blink-without-delay.html

PS: 馬達動作需要時間,記得中間還是得用 delay() 等它完成動作



samhuang 提到...

謝謝版大啊~~~
您真是太神了QQ

Cooper Maa 提到...

不客氣啊

blogger 留言板其實不太好用,網友要查詢或回覆留言都很麻煩
好像應該來架個討論區了,因為最近部落格留言愈來愈多
只是討論區不是架起來就好,還得花很多時間維護跟管理
討論區架是不架,真是傷腦筋啊

Sven Wang 提到...

請問Cooper,
情況:我在播放音樂的時候 也需要持續檢查某一個腳位的狀態

那麼放音樂的時候, 打算不使用delay
同時腳位狀態的訊息得知方式也不使用中斷(使用if)

這樣的情況下是否有方法可以達成我的需求?

Cooper Maa 提到...

hi Sven Wang, 好久不見

我沒用 Arduino 播放過音樂,你是指 MP3 Shield 之類的嗎?
sparkfun 上有個 mp3 shield
它的 example code 好複雜,而且看起來是 blocking IO,也就是會有 delay 的問題

剛找到 Bill Porter 貢獻的 Sparkfun MP3 Shield Arduino Library
從 Bill 的描述看來,這個 library 好像是 interrupt driven 的,所以在播放 MP3 的時候還可以做其它事耶
說不定這個 library 正是你要的