Arduino 專題教學-循線與避障自走車(下)

circuspi_循線避障自走車(下)

Arduino 自走車 – 循線與避障(上篇)」學會如何控制自走車行進後,本篇將依照循線與避障兩個主題分開說明,您可以依照自己購買的套件類型選擇對應的段落觀看。

避障自走車

首先安裝超音波在自走車上,如下圖先安裝超音波支架,用螺絲與螺帽固定。

安裝超音波支架
安裝超音波支架

將超音波塞進超音波支架對應的孔洞內,鬆緊程度會依照超音波模組上兩圓柱的距離,如果不幸拿到與支架孔洞吻合的,可以用熱溶膠稍微黏住,避免容易鬆脫。

將超音波與超音波架固定
將超音波與超音波架固定

接下來使用杜邦線將超音波連接到Arduino Sensor Shield V5.0 上,連接對應位子如下:

連接對應表
連接對應表
超音波
超音波
Arduino Sensor Shield V5.0
Arduino Sensor Shield V5.0

連接完畢後我們就可以開始來寫程式囉~首先打開上次撰寫的程式,並將不停重複內的程式移除,只要將原本的程式按右鍵刪除即可。

刪除不停重複內的程式
刪除不停重複內的程式

避障的程式流程是這樣的,首先讀取超音波偵測到的數值,接下來依照數值與我們設定的距離做比對。假設我們設定的距離是15cm,只要大於15cm 表示前方並沒有很靠近的障礙物,自走車可以維持前進的狀態,若是低於15cm 表示前方有障礙物,自走車此時需要閃避(左轉、右轉或後退)才不會撞到障礙物。

我們會習慣將讀取到的超音波數值存在變數裡,再使用變數去做距離比對,程式撰寫如下。

點選「變數」並按下「建立變數」。

點選「變數」並按下「建立變數」。
點選「變數」並按下「建立變數」。

設定變數的名稱,可以依照您的喜好取名稱,在本範例命名為「Distance」,輸入完成後按下右下角的確認。

設定變數名稱
設定變數名稱

確認完後即可在變數列看到剛剛設定的變數圖塊程式,將「變數「Distance」設為(0)」拉到不停重複內。

將「變數「Distance」設為(0)」拉到不停重複內

點選「偵測中…」並拉出「超音波距離感測器 trig腳位(1) echo腳位(1)」的圖塊程式到如下圖所示「設為(0)」的位置。

拉出「超音波距離感測器 trig腳位(1) echo腳位(1)」的圖塊程式到如下圖所示「設為(0)」的位置

將「trig腳位(1) echo腳位(1)」修改為我們實體超音波連接的腳位「trig腳位(3) echo腳位(2)」。此步驟就是將超音波偵測到的數值存在名為「Distance」的變數裡。

設定超音波腳位
設定超音波腳位

當我們獲得超音波偵測的數值後,就可以開始撰寫判斷距離的程式。點選「控制」,拉出如下圖的「如果( )那麼…否則…」的圖塊程式到剛剛變數程式的下方。

拉出「如果( )那麼...否則...」的圖塊程式

點選「運算」並拉出「( )大於(50)」的圖塊程式到下圖所示的位置。這個圖塊程式可以用來比對是否大於某個數字。

拉出「( )大於(50)」圖塊程式

將我們設定的變數「Distance」拉進「大於」前面的框框裡。

設定變數「Distance」在「大於」前面

並在「大於」的後方輸入我們設定的比對距離,單位為公分。在此範例以15cm 為設定值。依照程式上的意思將之前撰寫的「前進」程式放到「如果Distance 大於 15」的下方框內,並在「否則」下面的方框放入您想要的閃避動作,在此範例是放入「左轉」。

設定比對距離與指令

完成上面的程式後依照上篇的動作將程式上傳到Arduino UNO 裡,自走車將會開始移動。因為整個程式是放在不停重複內,所以自走車會一直讀取超音波的偵測值,讀取完畢後會放入變數並比對,再依照比對結果做出相對應的動作。只要超音波讀取到的距離比我們設定的15cm 還大,自走車將會一直往前走,反之則左轉。

您也可以修改比對的距離,或是遇到障礙物時閃避的程式,像是更改為右轉,或是先後退幾秒後再轉向幾秒……等,一連串的動作來閃避。

簡單的避障自走車玩法就介紹到此。

循線自走車

首先將循線感測器安裝在自走車上,循線感測器總共兩個,分別用來判斷左邊界與右邊界。安裝位置如下,因為感測距離有限,所以需用銅柱拉近與地面的距離。 

安裝循線感測器
安裝循線感測器
利用銅柱拉近與地面的距離
利用銅柱拉近與地面的距離
兩個循線感測器
兩個循線感測器

您一定覺得為什麼感測器要這樣擺?在這邊就不解釋了,等學成後再自己換位子比較差別。

我們必須先定義好哪邊是左邊,哪邊是右邊。以便我們後續寫程式時的方便性。在此將自走車放在桌上,循線感測器是朝下。將車頭朝前,左邊的感測器為左循線,另一個為右循線

接線如下表所示,不要接錯喔!

感測器上的A0 接腳不用接任何線,空著即可。

接線對應表
接線對應表

一切準備就緒後,我們先來看看自走車到底怎麼循線的吧!循線自走車顧名思義就是會沿著線移動的自走車,那是沿著什麼線呢?答案是黑線之所以是黑線,而不是其他顏色的線,與感測器的偵測有關

循線感測器上有一個紅外線發射與一個紅外線接收,當紅外線發射出的光打在可以反射的面上時,紅外線接收就會收到反射的光,此時Arduino 收到的訊號為0

若是紅外線發射出的光打在無法反射的面,使得紅外線接收沒有收到反射光,此時Arduino 收到的訊號為1 ,那什麼面會無法反射呢? 比方說面凹凸不平,導致反射光無法正確被接收到,或是有收到反射光,但強度太弱導致無法判別。

另一個原因是面的顏色導致光被吸收而無法反射,沒錯!就是黑色!本次教學將會以2cm 寬的黑色絕緣膠帶(電工膠帶)當作自走車要循的線

那知道感測器怎麼偵測後,到底自走車是怎麼巡線的呢?自走車在巡線的過程中,總共會遇到四種情況,如下圖共有A、B、C、D 四種,代表感測器們在黑線上的不同位置。

分別是:

A. 兩個感測器都在黑線上           B. 只有右邊感測器在黑線上

C. 兩個感測器都不在黑線上          D. 只有左邊感測器在黑線上。

感測器們在黑線上的不同位置

當遇到A 狀況時,因為感測器都在黑線內沒有任何一個出界,故對應的動作為前進。

當遇到B 狀況時,因為左感測器跑出黑線外,右感測器在黑線內,為了讓左感測器回到黑線內,故對應的動作為右轉。

當遇到D 狀況時,與B 狀況相反,因為右感測器跑出黑線外,左感測器在黑線內,為了讓右感測器回到黑線內,故對應的動作為左轉。

至於C 狀況,因為兩個感測器都跑出線,與B 狀況和D 狀況的出界不同,當兩個都出界時,我們無法知道是從左邊出界呢?還是右邊出界呢?所以我們先保留,不決定採取什麼動作!

我們只要將上圖四種狀況透過程式,分別寫出對應的動作,即可讓自走車沿著黑線走喔!

我們將以上四種情況如下表列出感測器在各情況的讀值:

循線感測器四種狀況得到的數值
循線感測器四種狀況得到的數值

打開上篇撰寫的程式,並將不停重複內的程式移除,只要將原本的程式按右鍵刪除即可。

移除不停重複內的程式

剛剛說過我們要把自走車會遇到的四種情況,透過程式寫出對應動作,所以首先要讀取兩個循線感測器的讀值,我們習慣將感測器讀值放入變數存起來,再由變數去比對遇到的是A、B、C、D 哪種情況。程式寫法如下圖所示:

點選「變數」並按下「建立變數」。

建立變數

設定變數的名稱,可以依照您的喜好取名稱,在本範例命名為「L」,用來儲存左邊的循線感測器讀值,輸入完成後按下右下角的確認。

設定新變數名稱

同樣的新增另一個變數叫「R」,用來儲存右邊的循線感測器讀值。

新增完畢後就能在變數列裡看到剛剛新增的圖塊程式,將「變數「L」 設為(0)」拉到不停重複內,再拉一個「變數「L」 設為(0)」到不停重複內,並將「L」 改為「R」 。

將變數拉進不停重複內
變更變數名稱

接著點選「腳位」,將「數位埠(9)?」拖拉到如下圖兩個位置,並將數字改為我們感測器實際連接在Arduino Sensor Shield V5.0 的腳位,L 對應3,R 對應2 。

將數位複拉至對應變樹中

將兩感測器讀值存到變數後,接下來撰寫一系列的判斷式。如下圖從「控制」拖拉出「如果( )那麼...否則...」的圖塊程式到剛剛變數程式的下方。

拖拉出「如果( )那麼...否則...」的圖塊程式

並於「運算」裡藉由「( )等於(50)」以及「< >且< >」兩個圖塊程式組合成下圖右邊放在「如果」後面的比較式。

拖拉出「( )等於(50)」與「< >且< >」兩個圖塊程式

點選「變數」,將「L」、「R」分別拉出放到等於的前面,如下圖所示:

將「L」、「R」分別拉出放到等於的前面

到這邊為止,我們已經把第一種情況寫出來囉!如下圖所示,A 狀況表示兩個紅外線都在黑線內,也就是讀值都為1 的情況。在A 狀況下,為安全狀態,對應的動作如剛剛所述為前進!

A 狀況(L = 1,R = 1)
Arduino自走車循線設定A 狀況(L = 1,R = 1)

依照上圖程式的邏輯,如果遇到A 狀況(L = 1,R = 1)則執行前進,那「否則」裡面填入什麼呢?當然是剩下的三種情況囉!如下圖所示,我們會再插入一個「如果...否則...」去確認第二種情況,並照樣填入該對應情況的動作。下圖新增的是B 狀況(L = 0,R = 1),如果自走車遇到這個狀況,則對應的指令是右轉。

B 狀況(L = 0,R = 1)

我們將遇到需要左轉的D 狀況(L = 1,R = 0)也寫進去,如下圖所示:

D 狀況(L = 1,R = 0)

到這邊為止我們已經將四種狀況中的三種寫完了,也就是前進、左轉和右轉,接下來就是我們一開始說明時所保留的C 狀況,那遇到C 狀況我們該執行什麼動作呢?

答案是~沒有!

答案是~沒有!

答案是~沒有!

因為怕您不相信,所以打了一次複製了兩次!沒有是什麼意思?也就是說我們不需要讓自走車知道該做什麼。說到這裡您一定想說,難道他自己知道?這就要詳細說明一下整個程式對於自走車移動的流程了。

以剛剛寫的程式來說明,如下圖~當自走車啟動後,程式會將感測器讀到的資訊存在變數L 與R 裡,並透過「如果...否則...」依序做比對,比對到第一種就執行前進,第二種就右轉...以此類推。執行完一次動作後,變數會重新再存一次感測器資訊,然後再比對~不停重複。

重點來了!比對到第一種就前進,第三種就左轉,那如果遇到不是這三種的呢?因為我們並沒有指定給自走車除了這三種以外的情況,所以自走車不會做其他動作。不會做其他動作不是代表自走車會停下來,當我們對自走車下達前進指令時,自走車會立刻前進,若是沒有下達其他指令,則自走車會繼續做最後一次對它下達的指令。

試著想像一下,當自走車沿著線走時,若要出現像C 狀況這種兩個感測器皆跑出黑線外的情形,勢必一定會先經歷像B 狀況或D 狀況這種只有一邊跑出黑線的情況,才會有機會出現C 狀況,如下圖所示:

A.B.C三種狀況

以上圖當例子~當自走車處在A 狀況時,程式會下達前進指令,此時自走車前進。接著因為遭遇轉彎,自走車遇到B 狀況,程式會下達右轉指令,此時自走車右轉。但在自走車右轉時因為車速太快,導致還來不及回到線內就遭遇到C 狀況,但因為我們並沒有針對C 狀況寫對應的程式,所以自走車此時的動作是什麼呢?沒錯~就是最後下達的指令~右轉!即便已經跑出去,但因為目前指令是右轉,所以自走車依舊會轉回去線內。

這就是為什麼四種情況我們只寫三種的原因,因為對於單純的循線來說根本不需要考慮C 狀況,前提是不能有類似直角或銳角彎的路線

將程式上傳到Arduino 後,放到利用黑色絕緣膠帶貼出路線吧!若上述步驟都沒做錯,您應該就能看到自走車沿著黑線走了。

相信您應該已經學會如何讓自走車沿著黑線移動,但自走車看起來似乎走得並不順暢~對吧!原因出在轉彎的方式,我們仔細回想第一篇所教的轉彎方式,如下圖~這是我們現在的轉彎方式,透過一顆馬達往前轉,另一顆往後轉的方式讓自走車改變方向。但這種改變方向的方法會造成自走車不論左轉或右轉時都會停在原地,您可以斷電後手轉自走車的兩個輪子就會明白了。若是透過下圖這種轉彎方式,就會造成自走車遇到A 狀況時移動,遇到B 或D 狀況時因為需要改變方向的關係,而看到自走車像停在原地般修正轉向。

設定自走車預到B/D狀況時左右轉

若想改變轉彎時彷彿停下來的窘境,我們就得換個方式。當遭遇需要轉彎時,原本向前轉的馬達繼續往前轉,而另一顆原本向後旋轉的馬達則改為停止,左、右轉修改後如下圖~

設定左右轉時馬達旋轉速度

可不要小看這樣簡單的調整,將程式上傳後實際讓自走車跑一次就知道了~天差地別!

新的轉彎方式不像原本是在原地修正,修正方向的同時也在移動,使得自走車行進過程中,相較舊方法變得更有效率。

簡單的循線自走車玩法就介紹到此。