Beetle 树莓派RP2350 - 步进电机驱动

Beetle 树莓派RP2350 - 步进电机驱动

🧭 本文介绍了 DFRobot Beetle RP2350 开发板实现步进电机驱动的项目设计,主要包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态三部分。

项目介绍

🌎 包括步进电机原理、该项目使用的 28BYJ-48 步进电机,及其驱动器——ULN2003 驱动模块介绍。

步进电机原理

🗺️ 步进电机(Stepper Motor)是一种将电脉冲信号转换为精确角度位移的执行器件,属于开环控制电机

在这里插入图片描述

🏝️ 核心特点:每接收一个脉冲,转子就转动一个固定的角度(称为“步距角”),无需反馈传感器即可实现位置控制。

  1. 结构组成
    • 定子:绕有线圈的磁极,分为多相(常见2相、4相、5相)。
    • 转子:永磁体(永磁式)或齿状铁芯(反应式/混合式)。
    • 定子绕组按特定顺序通电,产生旋转磁场,吸引转子逐步转动。
  2. 工作过程
    • 通过控制器(如单片机)发送脉冲信号,驱动电路按顺序切换定子绕组的电流方向。
    • 每切换一次,转子转动一个步距角,连续脉冲使电机连续旋转。

28BYJ-48 步进电机

🏡 28BYJ-48 是一款常见的低成本、小扭矩 5 线单极步进电机,可使用 ULN2003 控制器和单片机实现旋转控制,广泛用于打印机、扫描仪、摄像机云台、空调、家电、玩具、消费电子等领域。

参数
参数值/描述
电机类型单极 4 相永磁式步进电机(5线制)
步距角5.625°(64 步/圈),配合减速齿轮后 0.0879°(实际输出轴 4096 步/圈)
减速比1:64(内部齿轮组减速)
额定电压5V 或 12V DC
相电流约 100mA(每相)
保持扭矩约 0.1 N·m(输出轴,受减速齿轮影响)
绕组电阻约 50Ω/相

🔍 实际输出轴步距角为 5.625°/64 ≈ 0.0879°,转一圈理论上需要 64×64=4096 步,实际可能存在误差。

详见:28BYJ-48 数据手册 .

ULN2003 驱动器

🚄 ULN2003 是一款常用的达林顿晶体管阵列芯片,专为驱动高电流负载(如继电器、步进电机、LED阵列等)设计。其作用是将 MCU 输出的弱电流信号转换为大电流输出,是控制 28BYJ-48 步进电机的核心驱动芯片。

在这里插入图片描述

原理图

在这里插入图片描述

✅ 使用时需要将 28BYJ-48 步进电机的5线快接插头与 ULN2003 模块对应接口连接,并将模块的 4 个控制引脚(信号输入端,丝印 IN1、IN2、IN3、IN4)与单片机对应引脚相连,实现控制信号输入。

❤️ 详见:ULN2003A 数据手册 - Texas Instruments .

项目方案

⌛🔁⏳ 具体执行方案和工程测试流程如下

  1. 步进电机原理 🚀
  2. 旋转角度的精确控制 🛰️
  3. 串口发送实现自定义角度旋转 ✈️
  4. OLED 显示旋转状态 🚁

#1 旋转指定角度

🛵 本节介绍并实现了指定角度的步进电机旋转控制。⏱️

硬件连接

  • GP0 ---- IN1 (ULN2003)
  • GP1 ---- IN2 (ULN2003)
  • GP18 ---- IN3 (ULN2003)
  • GP19 ---- IN4 (ULN2003)

在这里插入图片描述

流程图

在这里插入图片描述

代码

'''
Name: Stepper Motor driven by ULN2003
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom angle.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
18 ---- IN3 (ULN2003)
19 ---- IN4 (ULN2003)
Ref: https://pico.nxez.com/2023/11/24/how-to-use-the-stepper-motors-on-raspberry-pi-pico.html
'''

from machine import Pin
import utime

# 电机控制引脚
coils = [
    Pin(0, Pin.OUT),  # A相 (IN1)
    Pin(1, Pin.OUT),  # B相 (IN2)
    Pin(18, Pin.OUT),  # C相 (IN3)
    Pin(19, Pin.OUT)   # D相 (IN4)
]

# 四相八拍步进电机的顺序值
STEP_SEQ = [
    [1, 0, 0, 1],  # AB'
    [1, 0, 0, 0],  # A
    [1, 1, 0, 0],  # AB
    [0, 1, 0, 0],  # B
    [0, 1, 1, 0],  # BC
    [0, 0, 1, 0],  # C
    [0, 0, 1, 1],  # CD
    [0, 0, 0, 1]   # D
]

'''
驱动电机旋转指定步数
:param steps: 正数=顺时针,负数=逆时针
:param delay_ms: 步间延时(ms),控制转速
'''
def step_motor(steps, delay_ms=1):
    direction = 1 if steps >=0 else -1
    for _ in range(abs(steps)):
        for phase in range(8)[::direction]:  # 方向控制
            for coil, state in zip(coils, STEP_SEQ[phase]):
                coil.value(state)
            utime.sleep_ms(delay_ms)

# 旋转角度控制
def rotate_angle(angle):
    steps_per_rev = 509
    steps = int(angle * (steps_per_rev / 360))
    step_motor(steps)

# 释放电机扭矩
def release():
    for coil in coils:
        coil.value(0)

while True:
    #rotate_angle(1) # 以单步方式持续转动
    rotate_angle(180) # 逆时针
    release()
    utime.sleep_ms(2000)
    rotate_angle(-90) # 顺时针
    release()
    utime.sleep_ms(2000)

效果

在这里插入图片描述

✨ 由供电处的电压-电流计量工具可知,当步进电机旋转工作时的功率约为 1W

#2 串口自定义角度

🌈 在实现步进电机旋转驱动的基础上,进一步实现串口发送自定义角度并旋转的功能设计方案。

硬件连接

  • GP0 ---- IN1 (ULN2003)
  • GP1 ---- IN2 (ULN2003)
  • GP4 ---- IN3 (ULN2003)
  • GP5 ---- IN4 (ULN2003)
  • GP8 ---- RXD (CH340)
  • GP9 ---- TXD (CH340)

在这里插入图片描述

流程图

在这里插入图片描述

代码

'''
Name: Stepper Motor rotate custom angle from serial
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom angle from UART.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
4 ---- IN3 (ULN2003)
5 ---- IN4 (ULN2003)
8 ---- RXD (CH340)
9 ---- TXD (CH340)
'''

from machine import Pin, UART
import utime
import ujson

# 电机控制引脚
coils = [
    Pin(0, Pin.OUT),  # A相 (IN1)
    Pin(1, Pin.OUT),  # B相 (IN2)
    Pin(4, Pin.OUT),  # C相 (IN3)
    Pin(5, Pin.OUT)   # D相 (IN4)
]

# 四相八拍步进电机的相序
STEP_SEQ = [
    [1, 0, 0, 1],  # AB'
    [1, 0, 0, 0],  # A
    [1, 1, 0, 0],  # AB
    [0, 1, 0, 0],  # B
    [0, 1, 1, 0],  # BC
    [0, 0, 1, 0],  # C
    [0, 0, 1, 1],  # CD
    [0, 0, 0, 1]   # D
]

# 驱动电机旋转指定步数;delay_ms 步间延时(ms),控制转速
def step_motor(steps, delay_ms=1):
    direction = 1 if steps >=0 else -1
    for _ in range(abs(steps)):
        for phase in range(8)[::direction]:  # 方向控制
            for coil, state in zip(coils, STEP_SEQ[phase]):
                coil.value(state)
            utime.sleep_ms(delay_ms)

# 角度控制
def rotate_angle(angle):
    steps_per_rev = 509
    steps = int(angle * (steps_per_rev / 360))
    step_motor(steps)

# 释放电机扭矩
def release():
    for coil in coils:
        coil.value(0)

# 串口控制旋转角度
def uart_control():
    uart = machine.UART(1, baudrate=9600, tx=Pin(8), rx=Pin(9))
    while True:
        if uart.any():
            cmd = uart.read()
            try:
                data = ujson.loads(cmd)
                rotate_angle(int(data['angle']))
                release()
            except:
                uart.write('Invalid command\r\n')
                release()
        else:
            release()
        utime.sleep_ms(100)

# main loop
while True:
    uart_control()

⚠️ 这里为了节能并提高效率,仅在串口发送正确指令时旋转,其他情况均释放步进电机扭矩,此时电流约为 0 .

效果

🐋 由于调用了 ujson 库,因此串口发送指令需符合 json 格式,如 {"angle":40} .

在这里插入图片描述

🆗 若串口发送 json 消息的格式错误,则反馈指令无效的提示。

在这里插入图片描述

#3 OLED 显示旋转状态

⏰ 在前面实现步进电机旋转驱动、串口自定义角度控制的基础上,进一步实现串口发送角度、旋转、OLED 状态显示的功能设计方案。

硬件连接

  • GP0 ---- IN1 (ULN2003)
  • GP1 ---- IN2 (ULN2003)
  • GP18 ---- IN3 (ULN2003)
  • GP19 ---- IN4 (ULN2003)
  • GP8 ---- RXD (CH340)
  • GP9 ---- TXD (CH340)
  • GP4 ---- SDA (OLED_SSD1306)
  • GP5 ---- SCL (OLED_SSD1306)

在这里插入图片描述

流程图

在这里插入图片描述

代码

'''
Name: Stepper Motor rotate custom angle from serial and OLED display
Version: v1.0
Date: 2025.05
Author: ljl
Other: Rotate stepper motor (28byj-48) for custom angle from UART, and OLED display the motor state in moving or steady.
Hardware connect:
0 ---- IN1 (ULN2003)
1 ---- IN2 (ULN2003)
18 ---- IN3 (ULN2003)
19 ---- IN4 (ULN2003)
8 ---- RXD (CH340)
9 ---- TXD (CH340)
4 ---- SDA (OLED_SSD1306)
5 ---- SCL (OLED_SSD1306)
Serial send style: {"angle": 40}
'''

from machine import Pin, UART, SoftI2C
import ssd1306 # OLED
import ujson # read uart string
import utime

# ==== Initialized IIC OLED ====
i2c = SoftI2C(scl=Pin(5), sda=Pin(4))
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

# display the motor state
def display_motor(angle,state):
    oled.fill(0)  # 清屏
    oled.text("Rotate Angle: ", 0, 0)
    oled.text("{:.1f} deg".format(angle), 20, 15)
    oled.text("State: ", 0, 35)
    if state == 1:
        oled.text("Rotating ...", 20, 50)
    elif state == 0:
        oled.text("Reset", 20, 50)
    else:
        oled.text("Error", 20, 50)
    oled.show()

# 电机控制引脚
coils = [
    Pin(0, Pin.OUT),  # A相 (IN1)
    Pin(1, Pin.OUT),  # B相 (IN2)
    Pin(18, Pin.OUT),  # C相 (IN3)
    Pin(19, Pin.OUT)   # D相 (IN4)
]

# 四相八拍步进电机的相序
STEP_SEQ = [
    [1, 0, 0, 1],  # AB'
    [1, 0, 0, 0],  # A
    [1, 1, 0, 0],  # AB
    [0, 1, 0, 0],  # B
    [0, 1, 1, 0],  # BC
    [0, 0, 1, 0],  # C
    [0, 0, 1, 1],  # CD
    [0, 0, 0, 1]   # D
]

# 驱动电机旋转指定步数;delay_ms 步间延时(ms),控制转速
def step_motor(steps, delay_ms=1):
    direction = 1 if steps >=0 else -1
    for _ in range(abs(steps)):
        for phase in range(8)[::direction]:  # 方向控制
            for coil, state in zip(coils, STEP_SEQ[phase]):
                coil.value(state)
            utime.sleep_ms(delay_ms)

# 角度控制
def rotate_angle(angle):
    steps_per_rev = 509  # 64步/拍 × 8拍 × 8相位
    steps = int(angle * (steps_per_rev / 360))
    step_motor(steps)

# 释放电机扭矩
def release():
    for coil in coils:
        coil.value(0)

# 串口控制旋转角度
def uart_control():
    uart = machine.UART(1, baudrate=9600, tx=Pin(8), rx=Pin(9))
    while True:
        if uart.any():
            cmd = uart.read()
            try:
                data = ujson.loads(cmd)
                ra = float(data['angle']) # rotate angle 
                display_motor(ra,1)
                rotate_angle(ra)
                release()
                display_motor(ra,0)
            except:
                uart.write('Invalid command\r\n')
                release()
        else:
            release()
            #display_motor(0,0)
        utime.sleep_ms(100)

# main loop
display_motor(0,0) # initialize OLED display
while True:
    uart_control()

效果

在这里插入图片描述

动态

在这里插入图片描述

总结

💠 本文介绍了 DFRobot Beetle RP2350 开发板实现步进电机驱动的项目设计,包括旋转角度的精确控制、串口发送实现自定义角度旋转、OLED 显示旋转状态等,为 Beetle-RP2350 的开发、设计和应用提供了参考。

彩蛋

🏳️‍🌈 介绍了 Beetle RP2350 开发板驱动 WS2812B 实现流水灯的项目设计。

WS2812B 流水灯

🍍 使用 neopixel 库实现 WS2812B 驱动。

WS2812 简介

🍒 WS2812 是一款集成了控制电路和发光电路的智能外控 LED 光源,通常被称为 “NeoPixel”(由 Adafruit 推广)。采用单线通信协议,能够实现全彩控制,广泛应用于 LED 灯带、装饰照明、创意项目等领域。

🌽 特点

  1. 集成驱动芯片
    • WS2812 将 RGB 三色 LED 和控制器集成在一个 5050 封装的芯片内,无需外部驱动电路。
  2. 单线控制(单总线协议)
    • 仅需 1 根数据线 即可控制多颗 LED,通过特定的时序信号传递颜色和亮度信息,支持级联。
  3. 24 位真彩色
    • 每个 LED 可独立设置 8 位(256 级)RGB 亮度,组合出约 1600 万种颜色。
  4. 响应速度快
    • 数据传输速率可达 800Kbps,刷新频率 400Hz,适合动态灯光效果。
  5. 低电压供电
    • 工作电压:3.3V–5V(推荐 5V),可直接由单片机驱动。
  6. 级联能力
    • 多个 WS2812 可串联,理论上仅受限于信号传输速度和电源功率。

🙏 优势:仅需 1 个 I/O 即可实现彩色灯带效果。

代码
'''
Name: WS2812 flow light by using neopixel
Version: v1.0
Date: 2025.05
Author: ljl
Other: include 3 effects: blink, flow lights and full-color running light.
URL1: https://electrocredible.com/neopixel-micropython-raspberry-pi-pico-ws2812b/
URL2: https://blog.csdn.net/jiangge12/article/details/128857863
'''

import neopixel
from machine import Pin
import time

ws_pin = 27
led_num = 8
BRIGHTNESS = 0.05  # Adjust the brightness (0.0 - 1.0)

neoRing = neopixel.NeoPixel(Pin(ws_pin), led_num)

# 定义亮度
def set_brightness(color):
    r, g, b = color
    r = int(r * BRIGHTNESS)
    g = int(g * BRIGHTNESS)
    b = int(b * BRIGHTNESS)
    return (r, g, b)
# -------------------------------------
# 流水灯函数
def color_wipe(color, delay):
    for i in range(led_num):
        neoRing[i] = set_brightness(color)  # 设置当前 LED 的颜色
        neoRing.write()  # 更新 LED 状态
        time.sleep(delay)  # 延时
    for i in range(led_num):
        neoRing[i] = (0, 0, 0)  # 关闭当前 LED
        neoRing.write()  # 更新 LED 状态
        time.sleep(delay)  # 延时
# 定义流水灯循环
def loop_wipe():
    color_wipe((255, 0, 0), 0.1)  # 红色流水灯
    color_wipe((0, 255, 0), 0.1)  # 绿色流水灯
    color_wipe((0, 0, 255), 0.1)  # 蓝色流水灯
# -------------------------------------
# 连续流水灯函数
def color_continue(color, delay):
    for i in range(led_num):
        neoRing[i] = set_brightness(color)  # 设置当前 LED 的颜色
        neoRing.write()  # 更新 LED 状态
        time.sleep(delay)  # 延时
# 定义连续流水灯循环
def loop_continue():
    color_continue((255, 0, 0), 0.1)  # 红色流水灯
    color_continue((0, 255, 0), 0.1)  # 绿色流水灯
    color_continue((0, 0, 255), 0.1)  # 蓝色流水灯
# -------------------------------------
# 定义闪灯循环
def loop():
    # Display red
    color = (255, 0, 0)  # Red color
    color = set_brightness(color)
    neoRing.fill(color)
    neoRing.write()
    time.sleep(0.5)
    # Display green
    color = (0, 255, 0)  # Green color
    color = set_brightness(color)
    neoRing.fill(color)
    neoRing.write()
    time.sleep(0.5)
    # Display blue
    color = (0, 0, 255)  # Blue color
    color = set_brightness(color)
    neoRing.fill(color)
    neoRing.write()
    time.sleep(0.5)

while True:
    #loop()
    #loop_wipe()
    loop_continue()
效果

🥗 RGB 三色流动点亮 🚦

在这里插入图片描述

🍭 全彩 RGB 流水灯设计,为后续项目增加美观的背景,突显赛博朋克风格。

😉 Markdown美化参考:EmojiAll中文官方网站 .

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值