Micromouse – ISR 怎麼寫? (一) & HC-SR04 探討

最近都在準備考試的東西,花在專案上面的時間變得很少… (但想做的東西真的好多…),連部落格很多時候都無法照期分享出來,感覺快要跟現在的生活暫時告別了,想到就難過…

Anyway 這不是重點,本篇以及下一篇的分享文我猜會是近期含金量數一數二高的,我會盡量分享我遇到和我在過程中學習到的東西 (嚴格來說是被 Bird 電後學到的東西哈哈)。

micromouse 上裝備 – HC-SR04

其實我一開始在和 Bird 討論專案內容時我有提過一個東西,一個我超級想玩的 SonicDisc: A 360° Ultrasonic Scanner (我本來想用這個做 slam <simultaneous localization and mapping>,真的超酷啊!),不過暫時被打槍,Bird 希望我先完成比較簡單的部分再往 slam 的方向走。

因此在 micromouse 上面裝上前左右,各三顆的 HC-SR04 就成為了目前專案的走向。

這時候便產生了一個問題,用 HC-SR04 三顆表示我需要至少 6 隻 digital I/O pin (trig 和 echo 各二),現在 UNO + CNC shield 擴充板,A4988 就用走了絕大多數的 digital pin,如圖:

螢幕快照 2017-12-20 下午5.04.49.png

目前用的 pin 腳其實只有 2, 3 (這個真的很剛好…真的是悲劇…往後會說明), 5, 6, 8 (分別是 stepx, stepy, dirx, diry, enable),總共 5 隻腳,但圖畫成這樣 (幾乎被用滿了的 UNO) 對於 CNC shiled 還不夠了解的我,只好詢問 Bird 其他的 pin 腳的作用。

果然是不夠了解,之前有提到,畢竟 CNC shield 是用來做 3D printer 居多,很少人像我一樣殺雞用牛刀,拿來做車子的控制,所以上面的 pin 9 – 13 基本上我都可以拿來用,再加上 pin 4 和 pin 7 因為我沒有用到 Z 軸的控制,當然也可以使用 (最後我根本沒有用到這麼多隻 pin,接下來會說明為什麼)

最後我選了 pin 4, 7, 9, 10, 11, 12 共 6 隻 pin 給各三顆超聲波 module 做使用。

ISR (Interrupt Service Routine) 要怎麼寫才對?

確定了 module 的接腳,接下來就是要跟步進馬達的 function 做連結,這就又跟 “時間” 的概念扯上關係了,步進馬達的驅動是依據 state 的變化 (如果忘記的朋友可以看看上一篇:Micromouse – 步進馬達實驗 有詳細的說明),多少時間產生一步,決定車子走多快,那如果現在加上 module 要去偵測與障礙物距離的 function,會怎麼樣?

螢幕快照 2017-11-21 下午6.37.04.png

答案是:馬達不如我預期的亂動,module 偵測到的數據全部都是 0.0。(現在回頭看都會覺得自己到底為什麼會這樣做,但當初真的就這樣做了…)

p.s 那超聲波的實作就寫成一個 function 我將其取名為 detection,利用大家可以在網路上輕易找到 HC-SR04 的 example code,動了點手腳,讓這個 sonar 的 function 可以吃參數,而這參數就是我前左右三顆的超聲波 module,return 的結果就是就為距離並放入三個 global variable 做存取。

回歸主題,其實原因很簡單,當步進馬達佔滿 main loop 的時候沒有其他東西跟步進馬達的 function 搶 main loop 的時間,但現在多了個 detection 的 function,表示步進馬達執行完一次後會接著執行 detection 的 function,等到 detection function 執行完後才會再回到步進馬達 function,中間就多了一段時間的等待 (對步進馬達 function 來說),那當然就不會順利的轉動,而是想像一下輪子邊轉邊一卡一卡的感覺。

既然要解決搶 main loop 時間的問題,根據我會的東西加上 Bird 的提醒,如果只是控制個馬達要佔滿 main loop 未免也太大材小用,浪費 main loop,所以我決定將步進馬達的 function 丟到 interrupt 做 (謹記:main loop 很寶貴,要拿到做最有意義的應用)。

我做過 ESP8266 的 timer interrupt 是利用大神在網路上寫好的 function,Arduino 官方也有提供 interrupt 的功能,我看到了兩個,分別是 Timer 和 attachinterrupt。我這裡先說結論,這是兩個完全不一樣的東西 (記得還被 Bird 電說,"Read the fucking manual",後續會提為什麼)

Anyway,繼續詳述我走過的路,我用了 Arduino Timer 的 library 順利的將步進馬達的 function 放到 interrupt 中執行,main loop 僅剩我的 detection function。

結果精彩的來了,全部都不會動,超聲波 module 讀數仍然是 0.0,步進馬達的輪子也不會轉了。

經過一個下午和 Bird 的討論和被電,也因為 Bird 懷疑我的 HC-SR04 本身就有問題,我對於這顆看似初學者的 module 有了更多的認識…。接下來會先分享 HC-SR04 的箇中奧秘,以及到底是哪裡出了問題。

HC-SR04 module 的重新認識

之所以會說重新認識就表示我不會只單單分享 HC-SR04 就是一個 trig 的 OUTPUT pin 加上一個 INPUT 的 echo pin,也不會只說 trig pin 有一個 State 的變化後會有 8 個 40KHz 的方波打出去,echo pin 接收到進而計算距離。

如果把 HC-SR04 這顆 module 的電路圖攤開來看,才會發現原來 trig pin 有一個 State 的變化 (至少 100ms) 這個動作是告訴 STC11 (HC-SR04 的 MCU) 要發射 8 個 40 KHz 的方波出去,接著就輪到大家在網路上可以輕易找到對於這顆超聲波模組的 “pulseIn()” function,這個 function 就是讓 echo 這根 INPUT pin 去偵測到剛剛 STC11 打出去的 8 個方波有沒有回來,function return 一個值讓 user 去算時間。

感覺上很懂了但其實細節並沒有搞清楚,首先,之所以是 8 個方波是有其目的的,現實生活中充滿著各種雜訊的干擾,echo pin 要怎麼知道 STC11 打出去的到底是什麼,而 8 個就是當初設計這顆 module 的前輩做的巧思 (不覺得很酷嗎!),而後又會再探討到更複雜的情況,比如說紅外線、無線電等傳輸是怎麼知道哪些訊息該收哪些不該收,這又會牽涉到 channel coding (這個小弟現在還早),先擺一邊。

再者,pulseIn() 這個 function 到底怎麼運作的 (其實會探討到這麼細也是因為和 ISR 有關係,之後說明!),pulseIn() 在我還沒真的拿示波器出來看的時候,我又 “想當然爾” 以為人家寫的 pulseIn(echo, HIGH),是 “echo pin 一直都是 LOW,等到收到 8 個方波才會變成 State HIGH”,如圖:

螢幕快照 2017-12-21 下午10.55.35

(上方自以為的 default 畫成圖長這樣,其實畫到這裡就該知道錯了…)

螢幕快照 2017-12-21 下午10.55.53

(上方自以為的 default 寫成 code 長這樣)

解釋一下程式碼,其實 pulseIn function 如果只是為了要實現剛剛那句話的作用,也就只是兩個 while loop 而已,第二個 while loop 很好理解,如果 state 一直都是 LOW 就給我待在迴圈內,直到 state 變 HIGH 再出來,而第一個 while loop 的作用是,由於 state 可能還在 HIGH 但下一個方波已經在此時藉由 tirg pin 被啟動,這樣永遠不會進 while echo state 為 LOW 的迴圈

結果發現是錯的…在 console 裡面會看到不論障礙物距離 module 多近多遠,顯示的數字都是 70 幾,這是為什麼呢?

用示波器一看才發現驚為天人的秘密,其實 echo pin 會在 trig pin 叫 STC11 打出方波後,經過一小段時間 echo pin 的 state 會被動地變成 HIGH 去偵測回來的 8 個方波,再把 state 變回 LOW,如圖:

螢幕快照 2017-12-21 下午11.08.23

(看完示波器後發現秘密的畫法長這樣)

螢幕快照 2017-12-21 下午11.09.28.png

(看完示波器後發現秘密的 code 長這樣)

所以我要應該是要避免 echo state 還在 LOW 的時候不能讓程式碼繼續往下跑,不然收不到東西,加上我是要算 state HIGH 持續的時間而不是 state LOW。

結論:會用跟真的懂完全是兩回事…,沒關係我路還長。

為了看到底是哪個環節讓 ISR 在運作的時候 detection function 不 work,進而深入探究這顆看似初學者的模組,後來也發現有一顆 module 的石英震盪器真的壞掉了,但還有兩顆應該要 work 才對阿???

去除了 module 本身的問題,那接下來就是要檢查 ISR 的寫法和 main loop 之間搭配的問題,篇幅已稍長,讓我們繼續看下去…。

4 thoughts on “Micromouse – ISR 怎麼寫? (一) & HC-SR04 探討

  1. 引用通告: Micromouse – ISR 怎麼寫? (二) – 自造者萊恩

  2. 引用通告: Micromouse – ISR 補充 & 淺談 PID 控制 – 自造者萊恩

  3. 您好 看完這篇文章後想詢問您 我們的目標是求出 duration是吧
    那實際上我們需要 Trig Low 到 echo AutoHigh的時間
    以及整段echo High 的時間。 最後再將兩者相加扣掉100us 就能得到Duration

發表留言