Upload
others
View
6
Download
0
Embed Size (px)
Citation preview
Arduino車循線避障設計研習營
主辦單位電資學院
承辦單位電機系
1
日期 時間 上課內容
850-900 開幕式
900-1030 Arduino自走車實際操作
1030-1040 休息時間
1040-1200 Arduino自走車循線原理與實作
1200-1300 午餐時間
1300-1420 Arduino自走車避障原理與實作
1420-1430 休息時間
1430-1630 Arduino 自走車避障避障實作及
頒發證書
12月26日將舉辦健行電資盃兩輪機器人循軌避障競賽
2
3
Arduino-微電腦控制板介紹Arduino 微電腦控制板大小為長70mm寬54mm核心使用
ATmega328P 八位元的微處理器
具有32K程式記憶體2k存取記憶體及1K可擦拭記憶體14個數位式輸出入端6 個類比式輸出入端支援USB SPII2C等資料傳輸
3
4
Arduino 軟體安裝
至官方網站下載Arduino軟體(免費)( wwwarduinoccenMainSoftware )
將軟體解壓縮到指定資料夾
在桌面建立Arduino捷徑
將Arduino UNO 連結上電腦
4
5
Arduino 官網
6
下載Arduino 軟體
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
日期 時間 上課內容
850-900 開幕式
900-1030 Arduino自走車實際操作
1030-1040 休息時間
1040-1200 Arduino自走車循線原理與實作
1200-1300 午餐時間
1300-1420 Arduino自走車避障原理與實作
1420-1430 休息時間
1430-1630 Arduino 自走車避障避障實作及
頒發證書
12月26日將舉辦健行電資盃兩輪機器人循軌避障競賽
2
3
Arduino-微電腦控制板介紹Arduino 微電腦控制板大小為長70mm寬54mm核心使用
ATmega328P 八位元的微處理器
具有32K程式記憶體2k存取記憶體及1K可擦拭記憶體14個數位式輸出入端6 個類比式輸出入端支援USB SPII2C等資料傳輸
3
4
Arduino 軟體安裝
至官方網站下載Arduino軟體(免費)( wwwarduinoccenMainSoftware )
將軟體解壓縮到指定資料夾
在桌面建立Arduino捷徑
將Arduino UNO 連結上電腦
4
5
Arduino 官網
6
下載Arduino 軟體
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
3
Arduino-微電腦控制板介紹Arduino 微電腦控制板大小為長70mm寬54mm核心使用
ATmega328P 八位元的微處理器
具有32K程式記憶體2k存取記憶體及1K可擦拭記憶體14個數位式輸出入端6 個類比式輸出入端支援USB SPII2C等資料傳輸
3
4
Arduino 軟體安裝
至官方網站下載Arduino軟體(免費)( wwwarduinoccenMainSoftware )
將軟體解壓縮到指定資料夾
在桌面建立Arduino捷徑
將Arduino UNO 連結上電腦
4
5
Arduino 官網
6
下載Arduino 軟體
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
4
Arduino 軟體安裝
至官方網站下載Arduino軟體(免費)( wwwarduinoccenMainSoftware )
將軟體解壓縮到指定資料夾
在桌面建立Arduino捷徑
將Arduino UNO 連結上電腦
4
5
Arduino 官網
6
下載Arduino 軟體
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
5
Arduino 官網
6
下載Arduino 軟體
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
6
下載Arduino 軟體
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
9
解壓縮
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
10
Arduino 軟體
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
11
啟動 Arduino
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
12
Arduino IDE
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
13
中文畫面
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
14
Arduino USB
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
15
Arduino 初體驗
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
16
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
17
程式驗證
按下
檢查程式語法是否正確但不保證功能正常
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
18
程式上傳
按下
將程式燒錄進Arduino
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
19
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
20
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
21
程式架構1註解2定義參數3Setup()初始化工作 ndash 放於主程式開始運作前
例如 IO腳設定 參數設定 啟動引用特定函式
4Loop函式主程式主程式會持續重複執行其內容直到Arduino電源被關閉
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
耶 我設計的第一個程式了(example_1)
實驗一 認識 Arduino操作
組別 第一組
姓名 王小明李大可
日期 20151107說明 設計將13腳位控制一個LED ON時間 OFF 時間可隨意設定
Arduino 微控制板的 Pin 13 腳已經有接一個 LED 無須另外接int led = 13 定義一個可存取記憶體名字叫 lsquoledrsquo 的 並將13存入
int ON_time = 300 設定LED ON時間
int OFF_time = 200 設定 LED OFF 時間
void setup( ) pinMode (led OUTPUT) 將led 設定為輸出 相當於設定13腳位為輸出
void loop( ) digitalWrite (led HIGH) led 腳位輸出 HIGHdelay(ON_time) 延續 300 毫秒
digitalWrite(led LOW) led 腳位輸出 LOWdelay(OFF_time) 延續 200 毫秒
22
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
程式的內容有以下幾個部分 1程式的標頭注解
開頭
內容包括 實驗名稱 作者 日期 文件說明等
結尾
單行注解
2 定義常數 define led 13 (程式設計者自訂)3 定義變數(暫存器) int led = 13 每行程式的結尾必須加上
變數區分為全域變數和區域變數兩種全域變數可應用於整個程式區域變數僅在設定該變數之程式區使用
4控制結構
void Setup( ) void loop( ) 5 程式 a = b + 5 6 函式(副程式) pinMode(led OUTPUT) (Arduino 函式庫提供)
delay(1000) (Arduino函式庫提供)Motor(100100) (程式設計者自訂)
常數 OUTPUT INPUT HIGH LOW (Arduino 設定常數)23
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
24
連續旋轉型RC伺服馬達Continuous Rotation Servo Motor
RC伺服機(馬達)
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
25
伺服馬達轉動特性
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
26
RC伺服馬達程式控制觀念
伺服馬達是由脈衝時間寬度來調控稱為脈波寬度調變(Pulse Width Modulation簡稱PWM)我們只要依照這樣時序送電壓脈波給RC馬達的訊號線(白色線)馬達就會按照我們的設定旋轉
脈波寬度是輸出高準位訊號 (High) 並維持時間所需時間(如下)控制訊號週期為20 毫秒 (Low) (ms)
脈波寬Pulse Width 轉向 Direction of Rotation13 ms 順時鐘轉
15 ms 停止轉動
17 ms 逆時鐘轉
P12
15 ms 15 ms
20 ms
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
27
Rotational Velocity vs Pulse Width for Servo
-60
-40
-20
0
20
40
60
1300 1350 1400 1450 1500 1550 1600 1650 1700
Pulse Width ms
Rot
atio
nal V
eloc
ity R
PM
Right Servo
伺服馬達轉速與脈波關係圖
可藉由改變脈波寬度對伺服馬達調控轉速
通常是 1500 plusmn 100 ms 就可以了
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
28
1啟動伺服馬達函式庫
2建立自己的伺服馬達函式庫
include ltServohgtServo myservo
之後就可以引用此函式庫內所預先設計好的函式例如
myservoattach( )myservowrite( )myservowriteMicroseconds()
28
引用Arduino伺服馬達函式庫
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
29
讓Arduino車乖乖聽話 (Example 2)
include ltServohgt 引入 servo 函式庫Servo servoLeft 宣告左邊伺服馬達servo 函式庫名稱叫做servoLeftServo servoRight 宣告右邊伺服馬達servo 函式庫名稱叫做servoright
int L_servoPin =12 左邊RC伺服馬達由D12控制int R_servoPin =13 右邊RC伺服馬達由D13控制
void setup( ) 建立初始功能servoLeftattach(L_servoPin ) 啟動D11腳位的左邊RC伺服馬達servoRightattach(R_servoPin) 啟動D12腳位的右邊RC伺服馬達
void loop( )servoLeftwriteMicroseconds(1600) 左邊伺服馬達 PWM 1600usservoRightwriteMicroseconds(1400) 右邊伺服馬達 PWM 1400us delay(2000) 前進 2s servoLeftwriteMicroseconds(1500) 左邊伺服馬達 PWM 1500usservoRightwriteMicroseconds(1500) 右邊伺服馬達 PWM 1500us delay(2000) 停止 2s
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
30
說明
使用Arduino特定功能函式庫或外掛的函式庫注意如下
1 若是Arduino自己的函式庫直接 include lt函式庫hgt若是外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
我們在使用循軌感測器時需要借用外掛的函式庫再介紹如何安裝外掛函式庫
2通常需要宣告誰引用函式庫方式如下 Servo servoLeft Servo servoRight
這樣 servoLeft servoRight 就可以分別引用Servo的函式庫內的所有函式
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
31
Servo函式庫提供可以隨時啟動或關閉伺服馬達的設定
servoLeftattach (L_servoPin ) 啟動servoLeft(左邊RC伺服馬達)servoRightattach (R_servoPin) 啟動servoRight(右邊RC伺服馬達)
Servo函式庫提供伺服馬達直接轉動到所需角度的函式例如
servoLeftwrite(pos) 這裡 pos 指轉動角度 0-180
這功能用於擺動式的伺服機擺動式伺服機外觀與連續轉動伺服馬達相同唯一不同處擺動式伺服機只能左右擺動180度
至於連續轉動伺服馬轉動的函式寫法如下
servoLeftwriteMicroseconds( ) servoLeftwrite( )servoRightwriteMicroseconds( ) servoRightwrite( )
( ) 內是PWM的時間單位 微秒(us) ( ) 內是角度單位 度若想讓伺服馬達反轉 ( )填入 1700 ( ) 填入gt 90 例如 180
伺服馬達正轉 ( )填入 1300 ( ) 填入 lt 90 例如 0伺服馬達停止 ( )填入 1500 ( ) 填入 90
PWM啟動後伺服馬達會一直運轉直到我們下達改變writeMicroseconds( )內的數值或關閉Servo函式庫指令為止
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
32
問題探討
1如果發現Arduino車該停止時沒有完全停止該如何調整
2 請問 若想讓Arduino 車 前進 2秒停止 2秒該怎麼設計3 請問 如何設計讓Arduino 車向後退4 請問 如何讓Arduino 車向左向右轉該怎麼設計5 如果 發現Arduino車走不直該如何調整
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
連續轉動伺服馬達靜止數值為1500us 但是由於內部回授機制誤差會出現些微轉動
若左邊馬達出現微向後轉可將1500每次向上加10us 微向前轉可將1500每次向減加10us 直到停止為止
若右邊馬達出現微向前轉可將1500每次向上加10us 微向後轉可將1500每次向減加10us 直到停止為止
void loop()servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us delay(2000) 停止 2s
請務必記住左邊伺服馬達 停止轉動 修正後為 xxxx us 右邊伺服馬達 停止轉動 修正後為 xxxx us
Arduino 車靜止調整(Example 3)
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
34
建立運動副程式開始設計自己的副程式 (運動副程式) (Example 4)
Arduino 車前進時左邊馬達反轉右邊馬達正轉因此我們定義所謂 ldquo前進rdquo的動作要求如下
void forward( ) 前進副程式servoLeftwriteMicroseconds (1600) 左邊伺服馬達前進
servoRightwriteMicroseconds(1400) 右邊伺服馬達 前進
void stoprun( ) 停止副程式servoLeftwriteMicroseconds(1500) 左邊伺服馬達修正為 xxxx us servoRightwriteMicroseconds(1500) 右邊伺服馬達修正為 xxxx us
void loop( ) 主程式forward( ) 呼叫前進副程式delay(2000) 前進時間stoprun( ) 呼叫停止副程式delay(2000) 停止 2s
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
設計自己的副程式設計副程式的目的首先是可以節省程式的空間將相同功能寫成一個
獨立的副程式使用時呼叫它來執行即可其次是讓程式變得簡潔好看及容易除錯
常見的 Arduino 副程式設計有以下4種型式
1 純粹呼叫副程式 無回傳執行結果 格式如下
void 副程式名稱 () 副程式內容
例如
void forward() 前進副程式
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
設計副程式(續)2 帶有傳遞參數的呼叫副程式 無回傳執行結果
void 副程式名稱 (參數) 副程式內容
例如
void forward(int times) 前進副程式 帶有需要的延遲時間
servoLeftwriteMicroseconds (L_forward ) 左邊伺服機前進
servoRightwriteMicroseconds(R_forward) 右邊伺服機 前進
delay(times) 前進時間
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
設計副程式(續)3 純粹呼叫副程式 但要回傳執行結果
回傳資料形式 副程式名稱 ()
副程式內容return 回傳資料
例如 呼叫超音波感測器副程式 進行前方障礙物掃描
int ultrasonic( ) example 12
超音波感測器前方掃描處理程式
return cm 回傳前方障礙物的距離
回傳資料形式 char byte int unsigned int long boolean
寫於 呼叫副程式的前頭
注意 若用 void 表示無回傳值
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
設計副程式(續)4 帶有傳遞參數呼叫副程式 回傳執行結果
回傳資料形式 副程式名稱 (參數)
副程式內容
例如 例如有兩個超音波進行前方障礙物掃描
int ultrasonic( int dir ) 呼叫超音波感測器 藉由dir決定是啟動哪個超音波
if (dir == left)啟動左邊超音波
else啟動右邊超音波
感測器前方掃描處理程式
return cm
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
39
建立運動副程式設計Arduino 車帶有時間參數的ldquo前進rdquo ldquo停止rdquo 副程式(Example 5)
void forward(int times) 前進副程式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void stoprun ( int times) 停止副程式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達 1500usservoRightwriteMicroseconds( R_stop) 右邊伺服馬達 1500us delay(times) 停止並等待時間
void loop() 主程式forward(2000) 前進 2 秒stoprun(2000) 停止 2 秒
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
40
Arduino車運行模式的討論
1 停止2 直線前進3 急速轉彎90度(小S) 以車軸中心旋轉(循軌轉彎使用)4 緩速轉彎90度(大S) 以一邊車輪為中心旋轉5 差速轉彎 (避障使用)5 直線後退6 以車軸中心180度迴轉
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
41
建立所有運動副程式(Example 6)
include ltServohgt 引入 servo 函式庫
Servo servoLeft 宣告左邊伺服馬達引用servo 函式庫
Servo servoRight 宣告左邊伺服馬達引用servo 函式庫(注意名稱不可重複)
int Left_Motor = 12 左邊RC伺服馬達由D12控制
int Right_Motor = 13 右邊RC伺服馬達由D13控制
int L_forward = 1600 左邊馬達前進int L_stop = 1500 左邊馬達停止int L_backward = 1400 左邊馬達後退
int R_forward = 1400 右邊馬達前進int R_stop = 1500 右邊馬達停止int R_backward = 1600 右邊馬達後退
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
42
void forward(int times) 前進函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達前進servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 前進時間
void backward(int times) 後退函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_backward) 右邊伺服馬達後退delay(times) 後退時間
void trunLeft(int times) 左轉函式servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉動時間
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
void trunRight(int times) 右轉函式servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void stoprun ( int times) 停止函式servoLeftwriteMicroseconds( L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds( R_stop) 右邊伺服馬達停止delay(times) 停止時間
void setup()servoLeftattach(Left_Motor) 啟動左邊伺服馬達
servoRightattach(Right_Motor) 啟動右邊伺服馬達
43
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
44
void loop() 主程式forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_s(750) 小s左轉
stoprun(1000)trunRight_s(750) 小s左轉
stoprun(1000)
forward(2000) 前進 2 秒stoprun(1000) 停止 01 秒trunLeft_S(1200) 大S左轉
stoprun(1000)trunRight_S(1200) 大S右轉
stoprun(1000)backward(2000)stoprun(100)
耶 我可以完全控制Arduino車囉
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
馬達左右轉方式的討論
void trunLeft(int times) 左轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_S(int times) 左轉函式(向前左轉 ) (大S)servoLeftwriteMicroseconds(L_stop ) 左邊伺服馬達停止servoRightwriteMicroseconds(R_forward) 右邊伺服馬達前進delay(times) 轉彎時間
void trunLeft_SS(int times) 左轉函式(向後左轉 ) (倒S)servoLeftwriteMicroseconds(L_backward ) 左邊伺服馬達後退servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
45
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
void trunRight(int times) 右轉函式(急轉) (小S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 後進delay(times) 轉彎時間
void trunRight(int times) 右轉函式 (大S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_stop) 右邊伺服馬達停止delay(times) 轉彎時間
void trunRight(int times) 右轉函式(倒S)servoLeftwriteMicroseconds(L_forward ) 左邊伺服馬達 前進servoRightwriteMicroseconds(R_backward) 右邊伺服馬達 停止delay(times) 轉彎時間
46
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
47
練習1 利用前進及左轉右轉副程式 讓控制Arduino車走L型
路徑(重點設計90度的轉彎)2 利用前進及左轉右轉90度的轉彎副程式 讓控制
Arduino車走以下路徑(每段時間3秒)
3 直線路徑來回走(重點利用(小S)設計180度的迴轉) (行走時間3秒)
47
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
48
馬達控制 參數法 (Example 7)
定義馬達參數 前進(100) 停止(0) 後退(-100)
左 右馬達參數組合如下( 0 0) 車子停止 ( 100 100) 車子前進 (-100 -100) 車子後退( 0 100) 前進左轉(大S)
(-100 0) 後退左轉 (大S)
(-100 100) 急速左轉 (小S)( 100 0) 前進右轉 (小S) (0 -100) 後退右轉 (倒S) (100 -100) 急速右轉 (倒S)
48
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
49
引用函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳
define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定 void setup()
MOTORON() 開啟 RC 伺服馬達功能
49
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
50
引用副程式 void MOTORON()L_motorattach(L_motor_pin) 啟動 L_motor_pin (D 11) 的伺服馬達
R_motorattach(R_motor_pin) 啟動 R_motor_pin (D 12) 的伺服馬達
void MOTOROFF()L_motordetach() 關閉接於 L_motor_pin 的伺服馬達
R_motordetach() 關閉接於 R_motor_pin 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左邊馬達送出 1500 + L (us)R_motorwriteMicroseconds(1500 - R) 右邊馬達送出 1500 - R (us)
50
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
51
主程式 void loop()
MOTOR(100 100) 車子前進
delay(1000)MOTOR(0 0) 車子停止
delay(1000)MOTOR(-100 -100) 車子後退
delay(1000)MOTOR(0 0) delay(1000)MOTOR(0 100) 前進左轉
delay(1000)MOTOR(0 0)delay(1000)
51
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
52
MOTOR(100 0) 前進右轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(-100 0) 後退左轉
delay(1000)MOTOR(0 0)delay(1000)MOTOR(0 -100) 後退右轉
delay(1000)MOTOR(0 0)delay(1000)
MOTOROFF() 關閉 RC 伺服馬達功能
delay(5000)
52
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
53
Arduino車循軌及避障設計
1 掌握系統的參數是設計的重點
2 使用感測器的性能要很清楚
3 如何用簡單易懂的方式呈現設計
4 如何提高感測速率避免影響準度
53
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
54
Arduino 車基本參數長(L)125 cm 寬(W)115 cm 高(H) gt75 cm
輪直徑(d) 67 cm
輪軸距前緣 25 cm
輪軸距後緣 100 cm
輪軸距紅外線感測器 35 cm
輪軸距超音波感測器 2 cm
Arduino 車使用RC伺服馬達
RC伺服馬為3pin接線 黑(地) 紅(+5v) 白(訊號)
RC伺服馬達轉數 45-50 rpm
以48rpm為基準 換算為 08rps 每秒08圈
每圈的長度 πd = 20 cm
車速 16 cms 或 625 mscm
54
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
55
問 急轉90度(小S) 換算車輪轉動多少圈(n)
耗時(T)多久
急轉車輪一邊前進一邊後退車子會以車軸中心為座標原點而旋轉
轉90度相當於車子以車軸為中心旋轉14圈長度既 14 π(W) 此時假如車輪轉動n圈長度既 nπd兩者相等(nπd = 14 πW )整理得知
n = 14 (Wd) = 025 (11567) = 04291圈T = 0429108 = 0536375 (S) = 536 (mS)
注意 必須考慮加減速摩擦力的問題實際值會略大於計算值
55
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
設計左轉90度(小S)有4種方法
1 直接設定小S左轉 再延遲90所需要時間(毫秒)Motor(-100 100) 設定小S左轉
delay(700) (執行)延遲700 毫秒
2設計左轉90度時間的副程式 turnLeft( int delay_time)
int delay_time = 700
呼叫左轉副程式参數為 delay_time 毫秒
void turnLeft( int delay_time)
Motor(-100 100) 設定小S左轉
delay(delay_time) 執行700 毫秒
如何設計左轉90度(小S)
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
3 設計左轉90角的副程式 turnLeft_angle(int angle )int angle90 = 700
void turnLeft( angleƟ) Motor(-100 100) 設定小S轉動方式
int delay_time = long(700) angleƟ 90delay(delay_time) 執行延遲毫秒
4 設計任意方向旋轉任意角度的副程式 turn_angle(angle) 正角度表示向右轉 負角度表示向左轉
void turn_angle( int angle) if ( angle gt 0 )
Motor(100 -100) 設定小S向右轉動
else Motor(-100 100) 設定小S向左轉動
int delay_time = long(700 (abs(angle)) 90 delay(delay_time) 執行延遲毫秒
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
58
問 緩轉90度(大S) 換算車輪轉動多少圈(n) 延遲時間(T)
緩轉車輪一邊停止一邊前進或後退車子以靜止車輪為座標原點旋轉
車子以一邊車輪為中心轉14圈長度即 14 π2W假如車輪轉動n圈長度即 nπd兩者相等整理得知
14 π(2W) = n π dn = 14 (2Wd) = 025 (2x11567) = 08582圈T = 0858208 = 107275 (S) = 1073 (mS)
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
59
認識循軌競賽
1 比賽車子有長寬高的限制(少數會有重量限制)
2 最短時間走完全程
3 全程不得遙控或接觸
4 車子必須放於起跑區內 聽哨音開始啟動
5 車頭離開起跑區接觸軌道開始計時
6 過程中車身不得全部離開軌道否則算出局
7 障礙區與斷線區例外但必須在指定區間內返回軌道
8 車頭接觸終點線停止計時
9 車子必須停於終點區內(有些未規定)
10 若規定時間內尚未回到終點則採計階段成績
59
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
60
認識比賽軌道
1 白底黑軌 或 黑底白軌
2 軌道寬度一般為 18cm plusmn 10
3 直角轉彎(L型路口)(迷宮)
4 圓弧轉彎(競速)
5 T字路口(迷宮)
6 十字路口(迷宮)(競速)
7 死巷(180度迴轉)(迷宮)
循軌避障算迷宮的一種
60
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
61
循軌研究
61
藉由感測器對軌道的追蹤讓車子可以一直保持在軌道上
顯然必須一直監視及控制車子左右微調讓車子不要偏離軌道
所以對於車子的調整能力感測器的性能及軌道特性必須弄清楚是循軌設計之首要
車子的調整能力必須實作逐步調整才能讓車子做出完美的追蹤
以下介紹感測器的性能
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
62
循軌感測器研究TQR-8RC 反射式感測陣列
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
63
bull TQR-8RC 反射式感測陣列使用5V電源
bull TQR-8RC 反射式感測陣列可以依需要調整使用個數本次將使用4顆感測器中間兩顆及最左最右 1顆
bull TQR-8RC 反射式感測陣列使用時離地距離(6-12mm)最佳10mm
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
64
認識感測器與循軌關係1 首先確定白色黑色何者是(High1) 何者是(Low0)
以TQR-8RC為例
偵測到黑色是(High1)而偵測到白色是(Low0)
2 以黑底白軌為例
出現0表示在軌道上
出現1表示離開軌道
3 循軌設計 兩個感測器 三個感測器 及 五個感測器等常見手法
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
65
黑白校準
bull一般比賽的環境都說是現場的燈光環境可是A場地換成B場地誰也沒保握燈光的條件都是一樣的
bull顯然不想要讓自己辛苦努力因為現場條件改變而毀於一旦
bull最好的概念就是賽前對針對現場的燈光環境進行校準這樣就可以降低意外的發生
bull循軌就是靠黑白來判斷是否在線上因此比賽前要找出紅外線對黑白的讀值是多少以它為基準就可以大大提昇判斷的準確性
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
66
什麼做黑白校準
假設沒有任何校準動作紅外線感測器對黑白的讀值分別是45V 及 23V
通常我們認為黑白的讀值是5V及0V 而以中間數25V為界線如此會發現黑色有(45V-25V=2V)的安全區域而白色只有(25V-23V=02V)的安全區域因此只要光源發生變化就容易出錯
若發現黑白的讀值分別是45V 及23V而以中間數 (45V+ 23V) 2 = 34V為界線如此黑色白色的安全區域一樣大(11V) 如此光源發生變化相對比較不容易出錯這就叫黑白校準
重點就是比賽前找出黑白的讀值再以中間值做為準線這樣就可以得到最大的安全區域
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
1 出售TQR-8RC 反射式感測陣列的POLOLU公司針對此產品提供了一個函式庫叫 QTRSensors 可以讓使用者進行黑白校準以提高對循軌的正確度
2 除了黑白校準外可以讓使用者可以彈性選用幾顆紅外線感測器可選 1-8顆
3 針對讀取紅外線感測器的處理 QTRSensors 提供方便的副程式
4 唯一不方便的是引用QTRSensors 函式庫必須額外的設定包括
1 使用紅外線感測器數量
2 感測器讀值時最長等待時間
3 驅動LED 接腳 D24 建立紅外線感測器的資料儲存區塊(矩陣)
67
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
68
建立TQR-8RC 函式庫範例include ltQTRSensorshgt 引用TQR-8RC函式庫
define NUM_SENSORS 4 使用紅外線感測器數量define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 驅動LED 接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
引用QTRSensors函式庫規定的寫法 QTRSensorsRC qtrrc為我們的函式名稱函式內容數位接腳位置 使用紅外線感測器數量 最長等待時間
驅動LED 接腳 4顆感測器分別接於數位接腳的 D3-D6
QTRSensorsRC qtrrc( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
69
使用 TQR-8RC函式庫說明這裡使用外掛的函式庫TQR-8RC函式庫
include ltQTRSensorshgt注意如下
1 使用外掛的函式庫則必須是先將函式庫放入Arduino的檔案夾裡的libraries資料夾裡
2引用TQR-8RC函式必須注意的地方
首先需要定義3個参數及一個儲存資料的矩陣方式如下
define NUM_SENSORS 使用紅外線感測器數量
define TIMEOUT 感測器讀值時最長等待時間
define EMITTER_PIN 驅動LED 接腳 D2unsigned int sensorValues[NUM_SENSORS] 資料儲存矩陣
這裡 unsigned int 為一種資料型態表示所存取的資料均為正數不具正負號
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
70
2宣告引用QTRSensors函式庫方式如下
QTRSensorsRC qtrrc ( (unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
誰引用函式庫 qtrrc 你可以改成你記得住的名稱
QTRSensors函式庫提供的功能如下1 qtrrccalibrate( )2 qtrrccalibratedMinimumOn[i]3 qtrrccalibratedMaximumOn[i]
i 表示 0 到 NUM_SENSORS的值4 qtrrcreadLine(sensorValues)
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
71
對TQR-8RC進行校準(example 8)
觀念做法 校準時讓車子左右各擺動90度
引用TQR-8RC 函式庫及定義參數
include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量 最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
72
引用Arduino車函式庫及定義參數include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達Servo R_motor 設定右邊馬達
define L_motor_pin 12 左邊馬達 arduino 接腳define R_motor_pin 13 右邊馬達 arduino 接腳
開機參數設定void setup( )Serialbegin(9600) 開啟監視視窗MOTORON() 開啟 RC 伺服馬達功能Calibration() 感測器校準delay(1000)
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
主程式void loop()qtrrcreadLine(sensorValues) 直接讀取TQR-8RC
Serialprint( LL = ) Serialprint(sensorValues[0]) 顯示 LL 讀值
Serialprint(t) Serialprint( L = ) Serialprint(sensorValues[1]) 顯示 L 讀值
Serialprint(t) Serialprint( R = ) Serialprint(sensorValues[2]) 顯示 R 讀值
Serialprint(t) Serialprint( RR = ) Serialprint(sensorValues[3]) 顯示 RR 讀值
Serialprintln()delay(250)
73
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
引用副程式 void MOTORON( )
L_motorattach(L_motor_pin) 啟動接於 pin 13 的伺服馬達
R_motorattach(R_motor_pin) 啟動接於 pin 12 的伺服馬達
void MOTOROFF( )L_motordetach( ) 關閉接於 pin 13 的伺服馬達
R_motordetach( ) 關閉接於 pin 12 的伺服馬達
void MOTOR(int L int R)L_motorwriteMicroseconds(1500 + L ) 左輪的PWM值
R_motorwriteMicroseconds(1500 - R) 右輪的PWM值
74
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
感測器校準 void Calibration()
define count_90 40 馬達轉90度的次數 請以實際測試值修正define count_180 80 馬達轉180度的次數 請以實際測試值修正
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(-50 50) 讓Arduino車向左緩慢旋轉for (int i = 0 i lt count_180 i++) 校準過程 向左180度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(50 -50) 讓Arduino車向右緩慢旋轉for (int i = 0 i lt count_90 i++) 校準過程 向右90度
qtrrccalibrate( ) 讀取所有紅外線感測器值
MOTOR(0 0) 車子停止
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
76
循軌設計
1兩個感測器循軌設計
2三個感測器循軌設計
3五個感測器循軌設計
感測器數量越多表示循軌越精細然而判斷的條件也變得複雜
無形中也增加設計的困難度
對於初學者應該盡量將問題簡化雖然可能造成循軌精度變差然而不影響整體功能表現
因此以下我們將以兩個感測器循軌為我們主要的設計
同時也使用兩個感測器做為路口判斷的設計
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
77
兩個感測器循軌設計
1兩個感測器距離大約09cm 若中間對準軌道中央則感測器相當於在軌道的14處及34處
2當左邊感測器出現HIGH時表示車子向左偏移14進行向右邊修正
3當右邊感測器出現HIGH時表示車子向右偏移14進行向左邊修正
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
78
循軌設計以中間2個感測器(LR)做為循軌
左右2個感測器(LLRR)做為路口判斷
各出現4種可能的狀況
78
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
79
循軌狀況討論
00 表示車子正好在軌道中央不用調整 繼續前進
01 表示車子偏右需要向左修正
10 表示車子偏左需要向右修正
11 表示離開軌道了一般設計讓車子停下來
11 有人設計讓它繼續前進例如有些比賽會設計斷線區
車子必須無偵測狀態下走過斷線區又回到軌道上
這是考驗車子直線行走能力
79
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
80
路口狀況討論
0 0 表示遇到T字路口或 十字路口
0 1 表示遇到左轉路口
1 0 表示遇到右轉路口
1 1 表示正常軌道上
80
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
81
循軌狀況為4選一的情況
Arduino語法 提供幾種分岔(多選一)處理式
1利用多個 if 條件式組合處理
2利用 if else 條件式的多選一處理
3使用 Swtich case的分岔(多選一)處理
81
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
82
if 條件式組合成多選一的處理
if(感測值 = = 00 ) 車子繼續前進 if(感測值 = = 01 ) 車子向左修正if(感測值 = = 10 ) 車子向右修正if(感測值 = = 11 ) 車子繼續前進
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
8383
例假設循軌感測器值存於 T_index
if (T_index = = 00) T_index = 00 表示車子在軌道中央處forward ( )
if (T_index = = 01) T_index = 01 表示車子在軌道偏右向左修正trunleft ( )
if (T_index = = 10) T_index = 10 表示車子在軌道偏左向右修正trunright ( )
if (T_index = = 11) T_index = 11 表示車子在斷線區維持前進forward ( )
if 條件式多選一處理範例
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
8484
if(軌道感測值 == 00 ) 車子繼續前進
else if(軌道感測值 == 01 ) 車子向左修正
else if(軌道感測值 == 10 ) 車子向右修正
else if(軌道感測值 == 11 ) 車子維持前進
else 車子前進
If else 條件式的多選一處理
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
8585
Switch (軌道感測值 ) case 00 車子前進
breakcase 01 車子向左修正
break case 10 車子向右修正
breakcase 11 車子維持前進
break其他 break
Swtich case 的分岔(多選一)處理
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
86
路口狀況 4選一的情況處理
以Swtich case 處理為例
Switch (路口感測值) case 00 視狀況 遇到T字路口或十字路口
breakcase 01 車子向左轉90度 遇到左轉路口
break case 10 車子向右轉90度 遇到右轉路口
breakcase 11 車子前進 正常軌道上
break其他 break
86
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
87
Arduino車TQR-8RC紅外線感測器循軌設計(Example 9)
功能說明 引入 4 個 IR 紅外線循軌設計
0 表示出現黑色 1 表示出現白色定義4個 IR 紅外線感測器名稱 LL L R RR
彎道偵測 (LL RR) LL 偵測軌道左彎 RR 偵測軌道右彎
循軌偏離偵測 (L R) 循軌偵測總共有4種組合 如下(00) 車子在軌上 (01) 車子偏右(10) 車子偏左(11) 車子不在軌上
彎道偵測總共有4種組合 如下(00) 出現十字路口或 T型路口(01) 左邊出現彎道(10) 右邊出現彎道(11) 正常軌道上
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
88
引用TQR-8RC 函式庫及定義參數 include ltQTRSensorshgt
define NUM_SENSORS 4 使用紅外線感測器數量最多到 8個define TIMEOUT 2500 感測器讀值時最長等待時間define EMITTER_PIN 2 LED 驅動接腳 D2
unsigned int sensorValues[NUM_SENSORS] 自訂變數矩陣
QTRSensorsRC qtrrc((unsigned char[]) 3 4 5 6NUM_SENSORS TIMEOUT EMITTER_PIN)
int LL L R RR T_index R_index level
引用Arduino車函式庫及定義參數 include ltServohgt 引入 RC 伺服機函式庫
Servo L_motor 設定左邊馬達
Servo R_motor 設定右邊馬達
define L_motor_pin 11 左邊馬達 arduino 接腳
define R_motor_pin 12 右邊馬達 arduino 接腳
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
開機參數設定 void setup()MOTORON() 開啟 RC 伺服機功能
MOTOR(0 0) Calibration() 感測器校準
MOTOROFF() delay(2000)MOTORON()
主程式void loop()
IRread() 讀取TQR-8RC Tracking() 循軌處理
Cross() 路口處裡
89
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
馬達副程式 感測器校準同前例
讀取軌道黑白值校準後
全黑值 = 1000全白值 = 0中間值 0 到 1000 之間
因此將黑白的分界值設為 500讀值 gt 500 視為讀到黑色
讀值 lt= 500 視為讀到白色
當出現白色將相對應的監視 LED 亮起來
當出現黑色將相對應的監視 LED 熄滅
這樣可方便觀測循軌及轉彎的現象
90
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
if (sensorValues[0] gt 500)LL = 1
elseLL = 0
if (sensorValues[1] gt 500) L = 1
elseL = 0
if (sensorValues[2] gt 500)
R = 1
else
R = 0
91
if (sensorValues[3] gt 500)
RR = 1
else
RR = 0
讀取軌道黑白值 void IRread()
unsigned int position = qtrrcreadLine(sensorValues)
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
92
循軌處裡 void Tracking()
T_index = L10+Rswitch(T_index)case 00 出現00表示軌道上
MOTOR(100 100) 車子繼續前進
breakcase 01 MOTOR(0 100) 01 表示車子偏右 向左修正
delay(25)break
case 10 MOTOR(100 0) 10 表示車子偏左 向右修正
delay(25)break
case 11 MOTOR(100 100) 表示在軌道外或斷線區
break default MOTOR(100 100) 其他
break
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
路口處理 void Cross()R_index = LL10 + RR
switch(R_index)case 00 出現表示在十字路口或T字路口上
MOTOR(0 0) 目前不處理
breakcase 01 表示出現左轉路口向左轉90度
MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(220)MOTOR(-100 100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) | |(R ==1))MOTOR(0 0) delay(50) break
93
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
case 10 表示出現右轉路口向右轉90度MOTOR(100 100) 向前行35cm 讓車軸移動路口
delay(250)MOTOR(100 -100) 小S旋轉直到 L R 感測器出現訊號為止
doIRread()
while ((L == 1) ampamp (R == 1))MOTOR(0 0) delay(50) break
case 11 MOTOR(100 100) 表示在軌道上
break default
MOTOR(100 100) 其他
break
94
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
循軌處理理念
首先將(L R)的讀值先轉成 0 或 1接著經由 T_index = L10+R 的運算 用來產生
00 01 10 11 四種狀況
再運用 swtich case 處理就可以
轉彎處理理念 相同
轉彎處理必須注意之處
就是偵測到轉彎訊號時 不可以立刻轉彎 這樣會發生轉彎動作提前容易造成出軌現象
解決方案
讓車子再向前走一小段路確定車軸到轉彎處再進行轉彎這樣可確保轉彎不出軌
轉彎到什麼情狀為止 有兩種做法
1 設計控制轉彎 90度(有把握正確轉90度)2 轉彎後 偵測 L R 感測器出現訊號為止 (不用理會轉90度)
95
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
96
避障設計
許多車子競賽中都會出現避障設計 就是當車子遇到避障物時自行必須閃避過去然後再繼續前進這方面的處理必須考慮以下問題
1 先確定車子距離障礙物多遠是可以安全旋轉的距離
2 採取向右迴避或向左迴避 依實境來決定或建議向右迴避
3 常見迴避技巧有直角迴避三角迴避及圓弧迴避3種方法
96
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
討論直角轉法bull 由直角示意圖得知當車子準備
再度回到軌道時若出現車子與軌道呈現90度這很容易讓車子離開轉彎的程序後回到循軌程序時誤判為T字路口而出錯
bull 解決的方法就是不要讓車子垂直回到軌道因此最後一次轉彎時記得小於90度如中間圖示
bull 最佳方案就是靠近軌道時再反方向轉個角度讓車子與軌道的夾角小於45度為最安全的作法如下圖所示
97
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
98
三直角方式避障設計
車子先轉45度角前進一段距離再反方向轉90的方式來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉45度
3 前進(障礙物大小一半 + 安全值)x(radic3 ~2倍)的距離
4 小S向左轉90度
5 前進(障礙物大小一半 + 安全值x(radic3 ~2倍)的距離
6 小S向右轉45度 (注意車尾不要碰到障礙物)
98
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
99
圓弧方式避障設計
利用車輪的速度差來避障 遇到避障物可採取向右迴避或向左迴避以向右迴避為例
1 先確定車子距離障礙物是可以安全旋轉的距離
2 小S向右轉90度
3 MOTOR(20 100)
4 前進圓弧180度
5 小S向右轉90度(注意車尾不要碰到障礙物)
99
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
100
避障感測器介紹
bull 超音波
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
101
超音波發射接收原理
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
102
超音波測距原理
室溫(250C)超音波速度約為 v = 3465 ms
假設被測物距離為 d (m) 超音波測得時間為 t(S) 兩者關係為 d = v t 2 = 0017325 t(us) (cmus)
換算成 d = t(us)58 (cm us)
V air = 3315+ (06xTC) ms
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
103
超音波測距程式範例(Example 10)
定義 超音波 ultrasonic 參數
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
int distance 存放超音波所測得距離
void setup( ) Serialbegin(9600) 開啟監視視窗pinMode (echoPin INPUT) echo 回波為輸入訊號pinMode (trigPin OUTPUT) trig 觸發為輸出訊號
void loop( )distance = ultrasonic( ) 呼叫超音波測距函式Serialprintln(distance) 將超音波測得距離顯示在監視視窗上
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
104
int ultrasonic( )digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
int echo_times = pulseIn(echoPin HIGH 15000) 讀回波時間
int echo_distance = echo_times 58 計算與物件的距離
return echo_distance 將結果回送
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
程式說明
由於數位接腳幾乎被用光了只剩下D11準備留給開關使用由於超音波使用兩個接腳只好將類比接腳當成數位接腳來使用Arduino 允許將類比接腳當成數位接腳使用編號從14-19所以 echo 及 trigger 設定如下
define echoPin 14 超音波訊號回波 Pin (A0)define trigPin 15 超音波觸發 Pin (A1)
超音波觸發訊號需要一個脈衝形式輸出因此超音波副程式開頭設計
digitalWrite(trigPin LOW) trigPin 腳 low 5uSdelayMicroseconds(5)digitalWrite(trigPin HIGH) trigPin 腳 high 10uS delayMicroseconds(10)digitalWrite(trigPin LOW) trigPin 腳 low
105
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
至於如何接收超音波回波(echo)訊號Arduino 提供一個專門處理輸入脈波寬度的函式供設計者使用
pulseIn(輸入腳位 偵測準位(HIGH 或 LOW) 最長等待時間(us) )
若不寫最長等待時間則會自動補上1 秒鐘
echotimes = pulseIn(echoPin HIGH 15000) Read in times pulse
超音波測距的換算
distance= echotimes 58 Calculate distance from time of pulse
106
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
注意 副程式的一種型態不同於 (void setup( ) )int ultrasonic( ) 呼叫副程式處理完畢後將結果回傳
helliphelliphelliphelliphellipreturn distance
主程式方面
distance = ultrasonic( ) 呼叫超音波測距函式
107
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
108
完整的範例因為程式太長
請直接看 程式例介紹
避障方法研究(I) 採用直角轉彎避障方式 (Examlpe 11)
避障方法研究(II) 採用三角轉彎避障方式 (Examlpe 12)
避障方法研究(III) 採取繞圓弧避障方式 (Examlpe 13)
練習後將舉行簡單的競賽
祝福各位有好成績
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
範例說明超音波參數設定 ultrasonic define echoPin_C 14 Pin to receive echo pulse (A0)define trigPin_C 15 Pin to send trigger pulse (A1)define near_dis 348 658define far_dis 522 958
我們定義遇到障礙物的起轉點為超音波距離障礙物6-9cm
原本可以使用前一個例子的程式換算超音波測距
echotimes = pulseIn(echoPin HIGH 15000) distance= echotimes 58 return echo_distance 將結果回送
109
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
最大的問題是Arduino對於除法運算會耗費很多時間由於車子是一直在前進的因此會造成算出起轉點時車子又向前走一段了
為了減少超音波處裡時間就不計算距離了直接回傳超音波測得的時間
int echo_times = pulseIn(echoPin HIGH 15000) distance= distance58 return (echo_times )
起轉點偵測 void Obstacle()forward_distance = Ultrasonic_Scan(echoPin_C trigPin_C) if ((forward_distance gt near_dis) ampamp (forward_distance lt far_dis ))
ObstacleON()
110
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111
111
本次研習課程
到此告一個段落
感謝大家的堅持
祝福各位收穫滿滿
111