< All Topics
Print

【制動】DC馬達 | dual2s-mini | MPY-LLM

簡介

我們無法使用微處理器、單晶片(MCU)等可程式微控器單元,直接控制致動器(電機、電磁閥…)或是較大功率元件,原因在於MCU的GPIO控制腳位是一種通用型的輸出輸入訊號處理設計思維,GPIO腳位對外的電流輸出能力(fan out)都相當微小,不足以驅動致動器等需要較大功率的元件。如下圖。解決的方法就是透過專化的處理電路,對應被控制元件(如直流電機、BLDC…)的特性進行功率放大、訊號回授、電路保護…等處裡。


準備

材料與工具

本文範例使用【dual2s-mini】為示範。如圖標註,每個DC電機接口可提供max 10V/ 800mA的推動能力。此電機接口可使用N20-6V/12V、TT馬達…等,或其他符合推動規格以內之電機。

延伸應用部分,由於此四組電機接口為獨立控制,是以也可以滿足全向輪的控制需求。


韌體範例

注意:驅動電機需要的電流較大些,請將鋰電池依規範極性方向安裝,方能正常驅動電機

DC電機規格限制:10V以下、耗電流800mA以下、瞬時堵轉電流1A以下。

單顆DC馬達正反轉與調速控制

from machine import Pin, PWM
import time

# 馬達引腳設定
M1A = PWM(Pin(14), freq=1000)  # G14 控制正轉
M1B = PWM(Pin(32), freq=1000)  # G32 控制反轉

def set_motor(speed, direction):
    """
    控制單顆馬達的速度與方向。

    參數:
    - speed: 轉速 (0 到 1023,1023為最高速)
    - direction: 方向 (1為正轉, -1為反轉, 0為停止)
    """
    #duty_cycle = int((speed / 100) * 1023)  # 將速度轉換為 0 到 1023 的 PWM 值
    if direction == 1:  # 正轉
        M1A.duty(speed)
        M1B.duty(0)
    elif direction == -1:  # 反轉
        M1A.duty(0)
        M1B.duty(speed)
    else:  # 停止
        M1A.duty(0)
        M1B.duty(0)

# 測試程式
if __name__ == "__main__":
    print("Testing single motor...")
    
    # 正轉,
    set_motor(300, 1)
    print("Motor forward at 50% speed")
    time.sleep(2)
    
    # 反轉
    set_motor(300, -1)
    print("Motor backward at 75% speed")
    time.sleep(2)
    
    # 停止
    set_motor(0, 0)
    print("Motor stopped")
    time.sleep(2)

    print("Test complete.")

from machine import Pin, PWM
import time

# 馬達引腳設定
M1A = PWM(Pin(14), freq=1000)  # 馬達 1 正轉
M1B = PWM(Pin(32), freq=1000)  # 馬達 1 反轉
M2A = PWM(Pin(12), freq=1000)  # 馬達 2 正轉
M2B = PWM(Pin(33), freq=1000)  # 馬達 2 反轉

def set_motor(motor, speed, direction):
   """
    參數:
    - motor: 選擇 "M1" 或 "M2"。
    - speed: 速度 (0 到 1023)。
    - direction: 方向 (1: 正轉, -1: 反轉, 0: 停止)。
    """
    if motor == "M1":
        forward, backward = M1A, M1B
    elif motor == "M2":
        forward, backward = M2A, M2B
    else:
        raise ValueError("Invalid motor. Use 'M1' or 'M2'.")
    
    if direction == 1:  # 正轉
        forward.duty(speed)
        backward.duty(0)
    elif direction == -1:  # 反轉
        forward.duty(0)
        backward.duty(speed)
    else:  # 停止
        forward.duty(0)
        backward.duty(0)

def stop():
    """停止車體。"""
    set_motor("M1", 0, 0)
    set_motor("M2", 0, 0)

def forward(speed):
    """車體前進。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, -1)

def backward(speed):
    """車體後退。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, 1)

def turn_left(speed):
    """車體左旋轉 (原地旋轉)。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, 1)

def turn_right(speed):
    """車體右旋轉 (原地旋轉)。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, -1)

# 測試程式
if __name__ == "__main__":
    print("Testing vehicle motion...")

    print("Forward...")
    forward(800)  # 50% 速度前進
    time.sleep(2)
    stop()

    print("Backward...")
    backward(500)  # 50% 速度後退
    time.sleep(2)
    stop()

    print("Turn left...")
    turn_left(500)  # 50% 速度左旋轉
    time.sleep(2)
    stop()

    print("Turn right...")
    turn_right(500)  # 50% 速度右旋轉
    time.sleep(2)
    stop()

    print("Test complete.")

from machine import Pin, PWM, time_pulse_us
import time

# 馬達引腳設定
M1A = PWM(Pin(14), freq=1000)  # 馬達 1 正轉
M1B = PWM(Pin(32), freq=1000)  # 馬達 1 反轉
M2A = PWM(Pin(12), freq=1000)  # 馬達 2 正轉
M2B = PWM(Pin(33), freq=1000)  # 馬達 2 反轉

#--------------------------------------------
# 超音波模組引腳設定
TRIG = Pin(27, Pin.OUT)
ECHO = Pin(13, Pin.IN)

def measure_distance():
    """
    使用超音波模組測量距離。
    返回距離值(單位:cm),若測量失敗則返回 -1。
    """
    # 發送觸發信號
    TRIG.off()
    time.sleep_us(2)
    TRIG.on()
    time.sleep_us(10)
    TRIG.off()
    
    # 計算回波時間
    duration = time_pulse_us(ECHO, 1, 30000)  # 最多等待30ms
    if duration < 0:
        return 500  # 無有效回波
    
    # 計算距離 (cm)
    distance = (duration / 2) * 0.0343  # 回波時間轉換為距離
    return round(distance, 2)

#--------------------------------------------
def set_motor(motor, speed, direction):
    """
    控制單顆馬達的速度與方向。
    
    參數:
    - motor: 選擇 "M1" 或 "M2"。
    - speed: 速度 (0 到 1023)。
    - direction: 方向 (1: 正轉, -1: 反轉, 0: 停止)。
    """
    if motor == "M1":
        forward, backward = M1A, M1B
    elif motor == "M2":
        forward, backward = M2A, M2B
    else:
        raise ValueError("Invalid motor. Use 'M1' or 'M2'.")
    
    if direction == 1:  # 正轉
        forward.duty(speed)
        backward.duty(0)
    elif direction == -1:  # 反轉
        forward.duty(0)
        backward.duty(speed)
    else:  # 停止
        forward.duty(0)
        backward.duty(0)

def stop():
    """停止車體。"""
    set_motor("M1", 0, 0)
    set_motor("M2", 0, 0)

def forward(speed):
    """車體前進。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, -1)

def backward(speed):
    """車體後退。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, 1)

def turn_left(speed):
    """車體左旋轉 (原地旋轉)。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, 1)

def turn_right(speed):
    """車體右旋轉 (原地旋轉)。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, -1)

# 測試程式-------------------------------------
if __name__ == "__main__":
    while True:
        distance = measure_distance()
        if distance <= 30:
            print("Distance: {} cm".format(distance))
            forward(300)
        else:
            stop()
        time.sleep(0.1)  
from machine import Pin, PWM, time_pulse_us
import time

# 馬達引腳設定
M1A = PWM(Pin(14), freq=1000)  # 馬達 1 正轉
M1B = PWM(Pin(32), freq=1000)  # 馬達 1 反轉
M2A = PWM(Pin(12), freq=1000)  # 馬達 2 正轉
M2B = PWM(Pin(33), freq=1000)  # 馬達 2 反轉

#--------------------------------------------
# 超音波模組引腳設定
TRIG = Pin(27, Pin.OUT)
ECHO = Pin(13, Pin.IN)

def measure_distance():
    """
    使用超音波模組測量距離。
    返回距離值(單位:cm),若測量失敗則返回 -1。
    """
    # 發送觸發信號
    TRIG.off()
    time.sleep_us(2)
    TRIG.on()
    time.sleep_us(10)
    TRIG.off()
    
    # 計算回波時間
    duration = time_pulse_us(ECHO, 1, 30000)  # 最多等待30ms
    if duration < 0:
        return 500  # 無有效回波
    
    # 計算距離 (cm)
    distance = (duration / 2) * 0.0343  # 回波時間轉換為距離
    return round(distance, 2)

#--------------------------------------------
def set_motor(motor, speed, direction):
    """
    控制單顆馬達的速度與方向。
    
    參數:
    - motor: 選擇 "M1" 或 "M2"。
    - speed: 速度 (0 到 1023)。
    - direction: 方向 (1: 正轉, -1: 反轉, 0: 停止)。
    """
    if motor == "M1":
        forward, backward = M1A, M1B
    elif motor == "M2":
        forward, backward = M2A, M2B
    else:
        raise ValueError("Invalid motor. Use 'M1' or 'M2'.")
    
    if direction == 1:  # 正轉
        forward.duty(speed)
        backward.duty(0)
    elif direction == -1:  # 反轉
        forward.duty(0)
        backward.duty(speed)
    else:  # 停止
        forward.duty(0)
        backward.duty(0)

def stop():
    """停止車體。"""
    set_motor("M1", 0, 0)
    set_motor("M2", 0, 0)

def forward(speed):
    """車體前進。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, -1)

def backward(speed):
    """車體後退。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, 1)

def turn_left(speed):
    """車體左旋轉 (原地旋轉)。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, 1)

def turn_right(speed):
    """車體右旋轉 (原地旋轉)。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, -1)

# 測試程式-------------------------------------
if __name__ == "__main__":
    myCnt = 0
    while True:
        distance = measure_distance()
        if distance <= 30:
            myCnt = 0
            print("Distance: {} cm".format(distance))
            forward(300)
        else:
            myCnt += 1
            if(myCnt > 2):
                myCnt = 0
                turn_left(250)
                time.sleep(0.1)
                stop()
            stop()
        time.sleep(0.1)
from machine import Pin, PWM, time_pulse_us
import time

# 馬達引腳設定
M1A = PWM(Pin(14), freq=1000)  # 馬達 1 正轉
M1B = PWM(Pin(32), freq=1000)  # 馬達 1 反轉
M2A = PWM(Pin(12), freq=1000)  # 馬達 2 正轉
M2B = PWM(Pin(33), freq=1000)  # 馬達 2 反轉
M3A = PWM(Pin(25), freq=1000)  
M3B = PWM(Pin(26), freq=1000)
M4A = PWM(Pin(22), freq=1000)  
M4B = PWM(Pin(23), freq=1000) 
#--------------------------------------------
# 超音波模組引腳設定
TRIG = Pin(27, Pin.OUT)
ECHO = Pin(13, Pin.IN)

def measure_distance():
    """
    使用超音波模組測量距離。
    返回距離值(單位:cm),若測量失敗則返回 -1。
    """
    # 發送觸發信號
    TRIG.off()
    time.sleep_us(2)
    TRIG.on()
    time.sleep_us(10)
    TRIG.off()
    
    # 計算回波時間
    duration = time_pulse_us(ECHO, 1, 30000)  # 最多等待30ms
    if duration < 0:
        return 500  # 無有效回波
    
    # 計算距離 (cm)
    distance = (duration / 2) * 0.0343  # 回波時間轉換為距離
    return round(distance, 2)
# -------------------------------------------
def boxing(speed):
    M3A.duty(speed)
    M3B.duty(0)
    M4A.duty(speed)
    M4B.duty(0)

def stop_boxing():
    M3A.duty(0)
    M3B.duty(0)
    M4A.duty(0)
    M4B.duty(0)
#--------------------------------------------
def set_motor(motor, speed, direction):
    """
    控制單顆馬達的速度與方向。
    
    參數:
    - motor: 選擇 "M1" 或 "M2"。
    - speed: 速度 (0 到 1023)。
    - direction: 方向 (1: 正轉, -1: 反轉, 0: 停止)。
    """
    if motor == "M1":
        forward, backward = M1A, M1B
    elif motor == "M2":
        forward, backward = M2A, M2B
    else:
        raise ValueError("Invalid motor. Use 'M1' or 'M2'.")
    
    if direction == 1:  # 正轉
        forward.duty(speed)
        backward.duty(0)
    elif direction == -1:  # 反轉
        forward.duty(0)
        backward.duty(speed)
    else:  # 停止
        forward.duty(0)
        backward.duty(0)

def stop():
    """停止車體。"""
    set_motor("M1", 0, 0)
    set_motor("M2", 0, 0)

def forward(speed):
    """車體前進。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, -1)

def backward(speed):
    """車體後退。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, 1)

def turn_left(speed):
    """車體左旋轉 (原地旋轉)。"""
    set_motor("M1", speed, 1)
    set_motor("M2", speed, 1)

def turn_right(speed):
    """車體右旋轉 (原地旋轉)。"""
    set_motor("M1", speed, -1)
    set_motor("M2", speed, -1)

# 測試程式-------------------------------------
if __name__ == "__main__":
    myCnt = 0
    while True:
        distance = measure_distance()
        if distance <= 30:
            myCnt = 0
            print("Distance: {} cm".format(distance))
            forward(800)
            if distance <= 10:
                boxing(1000)                
        else:
            myCnt += 1
            if(myCnt > 1):
                myCnt = 0
                turn_left(300)
                time.sleep(0.1)
                stop()
            stop()
            stop_boxing()
        time.sleep(0.1)  

Table of Contents