本文是 AI 神經網路自走車 第一篇,分享如何使用 Raspberry pi pico (RP2040) 做底層的馬達控制。透過 PWM 來控制馬達轉速,並使用 MicroPython 來撰寫韌體,就讓我們一起學習吧!
準備硬體元件
這次製作需要準備的材料為:
Step 1:了解馬達驅動模組
我的目標是做兩顆馬達的個別雙向控制(前進、後退)以此同時達到轉彎的效果, 因此選用 L9110 這個馬達驅動模組。
訊號輸入部分,除了 VCC 和 GND 外,還有兩組共四 pin,分別是 A-IA、A-IB 與 B-IA、B-IB。 A、B組分別透過 IA 、IB 訊號控制一顆馬達。
模組內建對 input pull high 10k 到 Vcc,如果馬達用 5V 而 MCU 是 3.3V 的話:
- 第一要確認 MCU 流入電流是否會過大。因為模組 pull high 到 5V,input 訊號電流會逆流到 MCU 的 pin (3.3V)
- 第二是馬達最大轉速只有約 3/5 (input 訊號壓差關係),所以必要的話做電壓轉換或是用光耦合隔離
從線路圖可以看出來,如果 IA = high,IB = low,馬達會往一個方向轉,反之 IA = low,IB = high 就會往另一個方向轉,如此即可控制方向。需注意的是實際方向會因為馬達連接的 output pin 有關,為了方便描述以下真值表簡單以正、反轉來描述。
IA | IB | 馬達轉向 |
0 | 0 | 停止 |
1 | 0 | 正 |
0 | 1 | 反 |
1 | 1 | 停止,但實測會導 致 Vcc 直接對地短 路,避免使用 |
Step 2:決定 pico 腳位
再來看看 pico 的 pinout,只要是淺綠色的都能當 PWM 輸出,超多 channel 任你選擇,pico 真是佛心來著!這邊我們以 GPIO 6, 7, 8, 9 來實作(對應到 pin 9, 10, 11, 12)
我們對照上面的 L9110 真值表和 pico 的 pinout 圖做以下連結
- GPIO 6 -> A-IA
- GPIO 7 -> A-IB
- GPIO 8 -> B-IA
- GPIO 9 -> B-IB
我們假定 A 組馬達是左邊馬達,B 組馬達是右邊馬達,所以由上面的配置可以得知每個 GPIO 的主要角色為
- GPIO 6 -> A-IA:控制左馬達正轉
- GPIO 7 -> A-IB:控制左馬達反轉
- GPIO 8 -> B-IA:控制右馬達正轉
- GPIO 9 -> B-IB:控制右馬達反轉
有以上硬體連結的設計後,我們進入韌體的設計
Step 3:撰寫 MicroPython 測試
首先進入 pico 的 python console,依照我們的硬體設計宣告對應 GPIO 為 PWM output pin
from machine import PWM, Pin
left_fwd = PWM(Pin(6))
left_bwd = PWM(Pin(7))
right_fwd = PWM(Pin(8))
right_bwd = PWM(Pin(9))
接下來我們要使用方法 duty_u16() 來控制 pwm duty,如同他的函數名稱
- 當傳入 65535 時,duty cycle = 100%
- 當傳入 32768 時,duty cycle = 50%
- 當傳入 0 的時候,duty cycle = 0%
因此我們可以用以下程式來測試
left_fwd.duty_u16(65535) # 左馬達會全速正轉
left_fwd.duty_u16(32768) # 左馬達會半速正轉
left_fwd.duty_u16(0) # 左馬達會停止
同理我們也可以測試反轉是否正常
left_fwd.duty_u16(0) # 先確保 left_fwd pin duty cycle = 0%
left_bwd.duty_u16(65535) # 左馬達會全速反轉
我們也可以用上述的指令來測試右馬達
right_fwd.duty_u16(65535) # 右馬達會全速正轉
right_fwd.duty_u16(32768) # 右馬達會半速正轉
right_fwd.duty_u16(0) # 右馬達會停止
right_bwd.duty_u16(65535) # 右馬達會全速反轉
如果都能正確運作,表示我們的硬體和韌體設計是一致的。
Step 4:將 PWM 控制包成類別
為了後續開發方便,我們將 PWM Motor 控制寫成一個類別 TwoWayMotor 來處理,重點描述如下:
- 在 TwoWayMotor init 的時候需要傳入 GPIO 的代號,讓他在類別內初始化 PWM pin
- 呼叫 set_speed() 時,傳入 speed 和 direction 來決定馬達的轉速和方向。
- 這邊將轉速以 0 ~ 100 來做控制,在內部轉換成 duty_16() 所需的值。
- 同時用全域變數 FORWARD 以及 BACKWARD 作為方向控制的參數來源。
from machine import PWM, Pin
_FULL_DUTY = 65535
FORWARD = 0
BACKWARD = 1
class TwoWayMotor:
def __init__(self, pin_forward: int, pin_backward: int):
self.pwm_f = PWM(Pin(pin_forward))
self.pwm_b = PWM(Pin(pin_backward))
self.pwm_f.duty_u16(0)
self.pwm_b.duty_u16(0)
# speed: 0 ~ 100
def set_speed(self, speed: int, direction: int):
if direction == FORWARD:
self.pwm_f.duty_u16(int(_FULL_DUTY * (speed / 100)))
self.pwm_b.duty_u16(0)
else:
self.pwm_f.duty_u16(0)
self.pwm_b.duty_u16(int(_FULL_DUTY * (speed / 100)))
經過包裝後,每一個 TwoWayMotor 可以代表一顆馬達,使用上就會比較簡單
left_motor = TwoWayMotor(6, 7)
right_motor = TwoWayMotor(8, 9)
left_motor.set_speed(30, FORWARD) # 左馬達正轉 30% 轉速
right_motor.set_speed(85, BACKWARD) # 右馬達反轉 85% 轉速
馬達底層介面開好後,我們就能往更高層的應用與控制邁進!如果覺得我文章內容對你有幫助的話,請在文章後面幫我按 5 個讚!讓我知道大家都喜歡什麼內容哦!
範例原始碼在此下載:github
AI 神經網路自走車
下一篇:用 Raspberry pi pico 與 HC-SR04 做超音波距離測量