用 Raspberry pi pico 做 PWM Motor Control

本文是 AI 神經網路自走車 第一篇,分享如何使用 Raspberry pi pico (RP2040) 做底層的馬達控制。透過 PWM 來控制馬達轉速,並使用 MicroPython 來撰寫韌體,就讓我們一起學習吧!

準備硬體元件

這次製作需要準備的材料為:

  1. Raspberry pi pico
  2. L9110

Step 1:了解馬達驅動模組

我的目標是做兩顆馬達的個別雙向控制(前進、後退)以此同時達到轉彎的效果, 因此選用 L9110 這個馬達驅動模組。

用 Raspberry pi pico 做 PWM Motor Control

訊號輸入部分,除了 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 訊號壓差關係),所以必要的話做電壓轉換或是用光耦合隔離
用 Raspberry pi pico 做 PWM Motor Control

從線路圖可以看出來,如果 IA = high,IB = low,馬達會往一個方向轉,反之 IA = low,IB = high 就會往另一個方向轉,如此即可控制方向。需注意的是實際方向會因為馬達連接的 output pin 有關,為了方便描述以下真值表簡單以正、反轉來描述。

IAIB馬達轉向
00停止
10
01
11停止,但實測會導
致 Vcc 直接對地短
路,避免使用
L9110 真值表
用 Raspberry pi pico 做 PWM Motor Control
L9110 與兩顆馬達連結示意

Step 2:決定 pico 腳位

再來看看 pico 的 pinout,只要是淺綠色的都能當 PWM 輸出,超多 channel 任你選擇,pico 真是佛心來著!這邊我們以 GPIO 6, 7, 8, 9 來實作(對應到 pin 9, 10, 11, 12)

用 Raspberry pi pico 做 PWM Motor Control
用 Raspberry pi pico 做 PWM Motor Control

我們對照上面的 L9110 真值表和 pico 的 pinout 圖做以下連結

  1. GPIO 6 -> A-IA
  2. GPIO 7 -> A-IB
  3. GPIO 8 -> B-IA
  4. GPIO 9 -> B-IB

我們假定 A 組馬達是左邊馬達,B 組馬達是右邊馬達,所以由上面的配置可以得知每個 GPIO 的主要角色為

  1. GPIO 6 -> A-IA:控制馬達
  2. GPIO 7 -> A-IB:控制馬達
  3. GPIO 8 -> B-IA:控制馬達
  4. 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 來處理,重點描述如下:

  1. 在 TwoWayMotor init 的時候需要傳入 GPIO 的代號,讓他在類別內初始化 PWM pin
  2. 呼叫 set_speed() 時,傳入 speed 和 direction 來決定馬達的轉速和方向。
  3. 這邊將轉速以 0 ~ 100 來做控制,在內部轉換成 duty_16() 所需的值。
  4. 同時用全域變數 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 做超音波距離測量

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。