Raspberry Pi Pico微控制板(二):MicroPython類比輸入與PWM輸出伺服馬達控制

本文將採用《超圖解Python物聯網實作入門:使用ESP8266與MicroPython》書本裡的範例,介紹Raspberry Pi Pico RP2040(以下簡稱Pico)、ESP8266和ESP32的MicroPython程式,在讀取類比輸入以及輸出PWM訊號的異同。

本文實驗需要的零件:

  • 樹莓派Pico開發板,一片。
  • 類比搖桿模組,一個(或者兩個10KΩ可變電阻)。
  • 9G伺服馬達,兩個。

Pico麵包板示範接線如下,搖桿的VRx與VRy腳分別接Pico的腳27(ADC1)和腳26(ADC0),兩個伺服馬達的訊號線則分別接腳17和16:

Pico麵包板類比搖桿和伺服馬達接線

MicroPython讀取類比輸入

ESP8266晶片的ADC(類比數位轉換器)的解析度(位元深度)是10位元,所以ESP8266的ADC物件的read()方法的傳回值介於0~1023。底下的程式片段將在ESP8266上每隔0.5秒讀取A0類比輸入:

from machine import Pin, ADC
import time
adc = ADC(0)
while (1):
   print(adc.read())
   time.sleep(0.5)

ESP32的ADC解析度為9~12位元可調,相關說明請參閱《使用ESP32控制板(三):MicroPython的類比輸入、UART序列埠以及觸控開關》貼文,底下的程式採12位元解析度,所以ADC物件的read()傳回值介於0~4095

from machine import Pin, ADC
import time
adc = ADC(Pin(32))
adc.atten(ADC.ATTN_11DB)
adc.width(ADC.WIDTH_12BIT)
while (1):
   print(adc.read())
   time.sleep(0.5)

由於MicroPython支援多款微控器,每個晶片的ADC解析度可能都不同,為了讓程式在不同晶片都能取得一致的類比輸入數值範圍,MicroPython 1.12版的ADC類別新增了read_u16()方法,它將統一傳回16位元,介於0~65535的類比輸入值。

Pico的RP2040晶片的ADC解析度也是12位元。read_u16()方法將把數值放大,例如,假設在ESP8266使用read()讀取到的類比值是512,改用read_u16()讀取,將變成32768。

Pico的RP2040晶片的ADC類別不支援read()方法,必須使用read_u16()。底下的程式片段將在Pico板每隔0.5秒顯示腳26的類比輸入值:

from machine import Pin, ADC
import time
adc = ADC(Pin(26))
while (1):
   print(adc.read_u16())
   time.sleep(0.5)

MicroPython輸出PWM訊號:控制伺服馬達

ESP8266和ESP32的PWM輸出程式寫法一樣,所以《超圖解Python物聯網實作入門:使用ESP8266與MicroPython》第10章的自訂伺服馬達控制類別(servo.py檔)可直接複製到ESP32執行。

但是同樣的程式檔在Pico的RP2040晶片會產生錯誤。首先是Pico的MicroPython版本,PWM()不接受freq(頻率)和duty(工作週期)參數。底下的敘述可在ESP8266和ESP32運行無誤:

from machine import Pin, PWM

servo = PWM(Pin(15), freq=50, duty=60)

PWM物件可用freq()和duty()方法設定頻率和工作週期:

from machine import Pin, PWM

servo = PWM(Pin(15))
servo.freq(50)
servo.duty(60)

在Pico板控制PWM輸出時,要採用上面的語法,duty()也要改用duty_u16(),而工作週期的輸入值範圍也改成0~65535。ESP8266和ESP32目前不支援duty_u16()方法。

底下是修改自第10章的servo.py伺服馬達自訂類別檔,適用於Pico板:

from machine import PWM, Pin

class Servo:
    def __init__(self, pin, min=500, max=2400, range=180):
        self.servo = PWM(Pin(pin))
        self.servo.freq(50)
        self.period = 20000
        self.minDuty = self.__duty(min)
        self.maxDuty = self.__duty(max)
        self.unit = (self.maxDuty - self.minDuty)/range

    def __duty(self, value):
        return int(value/self.period * 65535)

    def rotate(self, degree=90):
        val = round(self.unit * degree) + self.minDuty
        val = min(self.maxDuty, max(self.minDuty, val))
        self.servo.duty_u16(val)

請參閱《使用Thonny Python IDE編寫MicroPython程式(二):上傳程式與管理開發板的快閃記憶體內容》貼文的說明,使用Thonny編輯器把servo.py檔案存入Pico板的快閃記憶體,即可執行底下的程式,透過類比搖桿控制兩個伺服馬達:

from machine import ADC
from servo import Servo

servo_x = Servo(17)
servo_y = Servo(16)
scale = 0.00275
vr_x = ADC(27)
vr_y = ADC(26)

while True:
    servo_x.rotate(int(vr_x.read_u16() * scale))
    servo_y.rotate(int(vr_y.read_u16() * scale))
Posts created 470

2 thoughts on “Raspberry Pi Pico微控制板(二):MicroPython類比輸入與PWM輸出伺服馬達控制

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top