DIY Arduibot (8) --- 自製 Arduino 機器人 (8) --- IR object avoidance
紅外線障礙物迴避
有了紅外線做障礙物偵測, 那 Arduino 機器人就可以具有 障礙物迴避 的能力了.
就如之前所說的, 剛開始時, 我是用 VISHA 大顆的那種 IR receiver module,
後來嫌它大, 所以就換掉了.
這是第一版具有紅外線障礙物偵測的 arduino 機器人.
除了紅外線障礙物偵測外, 還有地面亮度偵測.
後來因為接線太多, 太過雜亂, 所以地面亮度偵測的電路先拆掉,
專心做紅外線的部分, 同時也把 IR receiver module 換成小的.
接收器很容易就收到一些反射光, 所以把 紅外線 LED 用電火布 (絕緣膠帶) 裹一裹,
控制照射範圍, 減少一些誤判的機會
很克難, 很陽春, 但是會動喔!
下面是具有障礙物迴避能力的 arduino 機器人程式,
動作很基本很簡單:
沒有障礙物時, 機器人保持前進,
左前方遇到障礙物時, 機器人順時鐘自旋, 繼續前進;
右前方遇到障礙物時, 機器人逆時鐘自旋, 繼續前進;
左和右前方都偵測到障礙物時, 機器人先後退, 順時鐘自旋, 繼續前進;
因為我把紅外線 LED 的光束限制在很小的範圍內,
所以比較低的障礙物會不容易偵測到, 機器人就會直接給他 勇往直前 衝!衝!衝!
晚點再拍個短片貼上來, 看看 Arduibot 會怎麼跑.
原理很簡單, 要怎麼發揮, 就看個人想像囉!
/******************************************************************
IR_ObjectDetection
Arduibot control
v1.0
Galileo (http://tw.myblog.yahoo.com/galileo-sky)
2010/6/6 (The IR object detection is improved.
******************************************************************/
#include <servo.h>
//---------------------------------------------------------------
// Digital OUTPUT/INPUT pins
//---------------------------------------------------------------
#define PIN_IR_E_RIGHT 6 //IR Emitter
#define PIN_IR_E_LEFT 7
#define PIN_IR_R_RIGHT 4 //IR Receiver
#define PIN_IR_R_LEFT 5
//---------------------------------------------------------------
//
//---------------------------------------------------------------
#define MAX_POS 180//170
#define MIN_POS 0//10
//For IR detection
#define OBJECT_DETECTED 0
#define OBJECT_NONE 1
#define DIFF_THRESHOLD 15
#define DETECT_THRESHOLD 4000
#define ADJ_TIME 1000 //ms
#define STOP_TIME 100 //ms
#define IR_FREQUENCY 38000 //IR carrier frequency
//---------------------------------------------------------------
// Servo objects
//---------------------------------------------------------------
Servo myservos[2]; // create servo object to control a servo
int ledPin = 13; // LED connected to digital pin 13
//---------------------------------------------------------------
//
//---------------------------------------------------------------
void setup() {
Serial.begin(9600);
// initialize the digital pin as an output:
pinMode(ledPin, OUTPUT);
myservos[0].attach(2); // Left servo
myservos[1].attach(3); // Right servo
pinMode(PIN_IR_E_RIGHT, OUTPUT);
pinMode(PIN_IR_E_LEFT, OUTPUT);
pinMode(PIN_IR_R_RIGHT, INPUT);
pinMode(PIN_IR_R_LEFT, INPUT);
digitalWrite(PIN_IR_R_RIGHT, HIGH);
digitalWrite(PIN_IR_R_LEFT, HIGH);
//tone(PIN_IR_E_LEFT, IR_FREQUENCY);
// prints title
Serial.println("Arduibot v0.1");
}
void loop() {
int nRightIR, nLeftIR;
int nIrResult;
nLeftIR = CheckLeftIR();
delay(10);
nRightIR = CheckRightIR();
nIrResult = nRightIR;
nIrResult |= nLeftIR<<1;
switch (nIrResult) {
case 0: //Both
Stop();
delay(STOP_TIME);
Backward();
delay(ADJ_TIME);
Stop();
delay(STOP_TIME);
RotateLeft();
delay(ADJ_TIME);
break;
case 1: //Left
Stop();
delay(STOP_TIME);
RotateRight();
delay(ADJ_TIME);
break;
case 2: //Right
Stop();
delay(STOP_TIME);
RotateLeft();
delay(ADJ_TIME);
break;
case 3: //None
Forward();
//delay(500);
break;
}
Serial.print("nIrResult = ");
Serial.println(nIrResult);
delay(100);
}
void Delay(int d) {
volatile int i, j=0;
for (i=0; i<d; i++)
j +=1;
}
//---------------------------------------------------------------
// Servo control
//---------------------------------------------------------------
void Stop() {
myservos[0].write(90); // tell servo to go to position in variable 'servoPos'
myservos[1].write(90); // tell servo to go to position in variable 'servoPos'
}
void Forward() {
myservos[0].write(150); // tell servo to go to position in variable 'servoPos'
myservos[1].write(30); // tell servo to go to position in variable 'servoPos'
}
void Backward() {
myservos[0].write(30); // tell servo to go to position in variable 'servoPos'
myservos[1].write(150); // tell servo to go to position in variable 'servoPos'
}
void TurnRight() {
myservos[0].write(150); // tell servo to go to position in variable 'servoPos'
myservos[1].write(80); // tell servo to go to position in variable 'servoPos'
}
void TurnLeft() {
myservos[0].write(110); // tell servo to go to position in variable 'servoPos'
myservos[1].write(30); // tell servo to go to position in variable 'servoPos'
}
void RotateRight() {
myservos[0].write(120); // tell servo to go to position in variable 'servoPos'
myservos[1].write(120); // tell servo to go to position in variable 'servoPos'
}
void RotateLeft() {
myservos[0].write(60); // tell servo to go to position in variable 'servoPos'
myservos[1].write(60); // tell servo to go to position in variable 'servoPos'
}
//---------------------------------------------------------------
// IR sensors
//---------------------------------------------------------------
int CheckLeftIR() {
int i;
//Pin 7
for (i=0; i<20; i++) {
//digitalWrite(7, HIGH);
PORTD |= 0x80;
asm volatile ("nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
::);
//j +=1;
delayMicroseconds(13);
//digitalWrite(7, LOW);
PORTD ^= 0x80;
asm volatile ("nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
::);
//j +=1;
delayMicroseconds(13);
}
return digitalRead(PIN_IR_R_LEFT);
}
int CheckRightIR() {
int i;
//Pin 6
for (i=0; i<20; i++) {
//digitalWrite(6, HIGH);
PORTD |= 0x40;
asm volatile ("nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
::);
//j +=1;
delayMicroseconds(13);
//digitalWrite(6, LOW);
PORTD ^= 0x40;
asm volatile ("nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
::);
//j +=1;
delayMicroseconds(13);
}
return digitalRead(PIN_IR_R_RIGHT);
}
文章標籤
全站熱搜

請問 ,arduino 端 是接再類比IO那邊嗎? 可否講解一下 ? [版主回覆07/18/2010 15:14:17]您好!

紅外線發射和接收都是接在數位端,
發射端純粹就是利用 38KHz high-low 的方波驅動 IR-LED,
接收則是用數位的 pin 腳監看 IR 接收模組的數位輸出信號,
當 IR 接收模組收到 38KHz 的紅外線時, 就會輸出 low 位準, 平常則輸出 high 位準.
因此判斷很單純.
希望這樣的說明有回答您的問題.
不好意思版大~ 我想要再請教一個問題 ~ 就是 我用的紅外線,是買套件的 (一包的那種) 可是 我實做出來發現發射端並沒有像版大那樣會發亮,而當接收端當我觸碰到正端 指示燈就亮了 請問是不是需要程式寫路才能讓發射端有動作? P.S 附上電路圖http://store.pchome.com.tw/hsiang-ho/M04554735.htm 來源:PChome (請板大幫幫小弟 ><感激~) [版主回覆07/31/2010 09:00:43]Hi 您好,
),

不好意思, 前幾天因為在國外, 無法回覆您的問題.
看了您的電路圖, 不清楚 IC1 是甚麼樣的IC,
但判斷不是使用 38KHz (或其他頻率) 載波調制過的紅外線發射源,
是使用連續發射的方式, 因此個人判斷接收端也應僅僅只是看看有沒有收到紅外線來做後續的控制,
使用這種方式的好處是簡單, 壞處是很容易受到環境光線干擾,
環境中到處都有紅外線光源, 所以接收端很容易收到外來光源的信號而產生誤判.
另外, 紅外線發光二極體所發射出來的紅外光線肉眼應該是看不到的 (除非有特異功能
你可以用數位相機 (或者是 DV) 對著發射端來看, 應該很容易看到, 通常看起來是藍紫色的.
以上是個人看法, 提供您參考, 希望對您有幫助.
版大您好~我的那個電路圖有實作出來了,謝謝版大~ 我想請教一下,就是版大讀的數據是由接收端 判別的嗎? 我在您的相簿中 有看到很像示波圖的程式 ,可以請版大跟我講一下怎嚜用嗎 0.0? 感激不盡= =" [版主回覆08/23/2010 08:35:15]恭喜您!

至於示波器圖形, 我有用到的工具有兩種: 一是示波器(是一部機器); 另一個則是利用 Arduino 以 ADC (類比轉數位) port 讀電壓, 然後以 RS232 傳到 PC 上, PC 上則使用 Processing 寫一個小程式接收 Arduino 傳來的資料將讀數畫出來, 如此而已喔!
不知道為什麼, 用 Chrome 上 Yahoo blog 寫 blog 就會有點怪怪的
,

更新一下這裡的內容
不好意思! 當初貼的時候沒貼好, Delay() 那個函式應該是這樣的:
void Delay(int d) {
volatile int i, j=0;
for (i=0; i<d; i++)
j +=1;
}
另外, 這函式主要是用來做延時的, 後來在整個程式裡並沒有使用到,
所以可以直接刪除掉了.
一直麻煩板大 感覺很不好意思=口= (話說 我也是用chrome 0.0) 原來是延遲用喔..(反覆看了好幾遍就是不知道延遲用在哪= =") 謝謝大大解惑喔><" [版主回覆08/30/2010 08:26:29]別客氣!

有興趣一起討論事很有趣的. 況且又可以溫故知新呢.
我想請問一下= =" >> PORTD |= 0x80 這個是記憶體的位址嗎0.0? 可以請教一下怎嚜算或是那個部份隨便給位址就好了? [版主回覆08/31/2010 07:59:35]您好: PORTD 是一個 register, 它控制 Arduino 的單晶片 (ATmega8, ATmega168 andATmega328) port D 的輸出. 因為在這個例子裡, 兩顆 紅外線 LED 是接在 Arduino 的 pin 6 和 7, 對應到 ATmega 單晶片的 PD6 和 PD7,所以呢, PORTD |= 0x40 會將 PORTD 的 Bit6 (PD6) 輸出為 high (點亮 紅外線 LED); PORTD ^= 0x40 會將 PORTD 的 Bit6 (PD6) 輸出為 low (熄滅 紅外線 LED), 同理, PORTD |= 0x80 會將 PORTD 的 Bit7 (PD7) 輸出為 high (點亮 紅外線 LED); PORTD ^= 0x80 會將 PORTD 的 Bit7 (PD7) 輸出為 low (熄滅 紅外線 LED), 之所以直接以 register 來控制而不用 Arduino 的 digitalWrite() 是為了能在最快的執行速度下精準控制 timing, 讓 紅外線 LED 的載波頻率是在所要的 38KHz.
您好:


不好意思, 剛剛又用了 Chrome 回覆, 所有的文字全擠在一起
PORTD 是一個 register, 它控制 Arduino 的單晶片 (ATmega8, ATmega168 andATmega328) port D 的輸出.
因為在這個例子裡, 兩顆 紅外線 LED 是接在 Arduino 的 pin 6 和 7, 對應到 ATmega 單晶片的 PD6 和 PD7,
所以呢,
PORTD |= 0x40 會將 PORTD 的 Bit6 (PD6) 輸出為 high (點亮 紅外線 LED);
PORTD ^= 0x40 會將 PORTD 的 Bit6 (PD6) 輸出為 low (熄滅 紅外線 LED),
同理,
PORTD |= 0x80 會將 PORTD 的 Bit7 (PD7) 輸出為 high (點亮 紅外線 LED);
PORTD ^= 0x80 會將 PORTD 的 Bit7 (PD7) 輸出為 low (熄滅 紅外線 LED),
之所以直接以 register 來控制而不用 Arduino 的 digitalWrite() 是為了能在最快的執行速度下精準控制 timing, 讓 紅外線 LED 的載波頻率是在所要的 38KHz.
剛剛注意到 #include 那行不完整, 修正了.
#include <Servo.h>
請問= = Servo 是啥= =?? 專門控制馬達的嗎? [版主回覆09/01/2010 21:57:30]您好,
servo 這個library 是專門用來驅動 RC (遙控用的) 伺服馬達 (RC servo),
伺服馬達 可參考我的這篇
http://tw.myblog.yahoo.com/galileo-sky/article?mid=1780&next=1774&l=f&fid=108
就大概知道它是甚麼了.
板大你好 我還有個 問題~ switch (nIrResult) 這裡case 的是0123 , 那請問一下0123是哪裡的??
另外就是asm volatile ("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ::); 可以講一下是作什麼用的嗎 ><
[版主回覆09/03/2010 09:53:20]您好!有關 switch (nIrResult), nIrResult 是由 CheckLeftIR() 和 CheckRightIR() 綜合偵測左右兩個 IR 接收器的結果而得.
asm volatile (...) 則是一段 assembly code (組合語言程式), 裡面很簡單, 只有幾行 nop (No-OPeration), 也就是說不做任何事, 但是每一個 nop 都會花費一個 clock cycle 的時間 (0.0625 us), 目的就是拖延時間,
和 delay 的作用是一樣的, 只是能更精確的拖而已.
請問 一下喔~ arduino 可以傳0或1 給 PC端嗎? 可以的話 大概要怎嚜寫= =? 可以交一下ㄇ [版主回覆10/08/2010 08:44:16]如果您是指用一般的數位輸出入介面 (GPIO), 想到的大概有兩種方式: 1. 透過 PC 的 printer port. printer port 有一些輸入信號接腳可用 2. 透過 PC 的 COM port. COM port 上也有一兩支腳位可用 這些都需要額外接線才能完成. 如果您是指用串列通信 (例如 PC-USB-Arduino): 因為在 PC 上看到的 Arduino 其實就是一個 COM port (virtual COM), Arduino 上的單晶片(ATmegaxx8) 和 PC 之間是利用 單晶片的 UART 透過板子上的 USB-UART bridge 晶片溝通的. 簡而言之, 只要USB線有連接著PC和Arduino, Arduino 的程式可就可以用 Serial 這個程式庫利用COM 和PC之間傳收資料. 這部分在 安裝好的Arduino 軟體裡有很多例子, 不仿參考或下載到板子上執行看看, 很簡單的.
因為我的車子是用WIF模組來遙控的,所以我的車子 不能接USB的PORT, 所以說 想請問一下 arduino 有沒有語法可以 傳0、1 給PC端(控制端)呢? [版主回覆10/08/2010 22:39:08]如果您是用TCP/IP , 是不是直接用WiFi 傳就可以了?
因為我們現在只是用 wifi模組 來接收pc端送出的指令,然後車子才會動, 可是現在想要知道車子(arduino)能不能發送訊息出來讓PC 端能夠接收 0.0" 希望板大能幫忙解惑一下= = [版主回覆10/09/2010 18:29:35]看來一定得用無線傳輸才行了.
我來想想看:
1. 如果您的Arduino 可接上 現有的 WiFi 模組(透用 UART, SPI 或者其他介面),
這樣就不需另外加其它的無線模組了
2. 如果不用現有的 WiFi 模組做傳輸, 就必須外加的無線模組. 可用 BlueTooth,
430 MHz 無線發射模組, 紅外線, 2.4 GHz 無線收發模組等等都可以,
要看實際的使用方式來決定, 比如說紅外線就無法隔著障礙物傳輸等.
我最近用 2.4GHz 無線收發模組在做些實驗, 這類的模組網拍上很多,
使用起來也很方便, 但要寫些程式, 可做雙向傳輸, 還蠻不錯的.
恩 我們現在有WIFI模組 , 主要是不知道送出訊息的程式要怎嚜寫= = [版主回覆10/13/2010 08:37:09]WiFi 模組我個人也沒有用過耶!

不過, 我想他和 mcu 間的介面不外乎 UART, SPI 這類的,
當然, 也得讀一讀 data sheet 看看有哪些溝通指令.
您不是用 WiFi 控制車子的行進嗎? 我想應該某種程度上已經做了一些連結了.
如果找得到範例程式, 拿來改一改會比較簡單些.
您好,請問可以要您所用的LED偵測原理圖嗎?
因為我弄了很多個,可是一直都沒反應~~'
方便請寄到wynn_ryest_g5@yahoo.com
謝謝