这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » let'sdo2026年第1期静音步进电机控制实践成果帖

共1条 1/1 1 跳转至

let'sdo2026年第1期静音步进电机控制实践成果帖

助工
2026-06-07 19:55:48     打赏

在上一个过程帖的基础上,完成进阶任务,在基础任务上实现:速度调节功能加速/减速控制按键或串口控制运动,例如:启动、停止、反转。以及,自由发挥方向(不做强制要求):梯形加减速控制多种运动模式定位控制(步数控制)PWM方式生成STEP

参考过程帖的接线方式,最后代码及展示效果如下,视频链接为https://b23.tv/BZQyX2d,实现了以下功能:


命令交互启动 (s / start)使能电机,进入加速段,开始运行

停止 (x / stop)立即停止电机,禁用使能,状态置为 stop

反转方向 (r / reverse)需停止状态下切换方向,修改方向引脚

加速 (+ / faster)减少目标脉冲间隔(提高目标速度),若正在运行则重新进入加速段

减速 (- / slower)增加目标脉冲间隔(降低目标速度),若正在运行则重新进入减速段

查看状态 (i / info)显示当前运行状态、方向、当前/目标速度、使能状态、位置

帮助 (h / help)打印所有可用命令
运动控制S曲线加减速加速段与减速段均使用正弦平方插值(S曲线),平滑启动与停止

三段式状态机支持 accelrundecel 自动过渡,以及手动干预时的状态重设

速度范围限制最快 MIN_DELAY_US (100µs),最慢 MAX_DELAY_US (5000µs)

启动速度可配置START_DELAY_US = 2000µs,避免急停或急启

加速/减速步数独立设定ACCEL_STEPS / DECEL_STEPS 均为 800 步,可独立调整
硬件驱动步进脉冲输出通过 GPIO 引脚 step 产生方波,脉冲宽度等于当前计算出的延迟

方向控制单独方向引脚,高低电平分别对应正反向

使能控制低电平有效,启动时使能,停止时禁能(节省功耗,防止误动作)
状态与计数位置累计每发一个脉冲更新 position,方向决定增减

总步数统计total_steps 累计所有已发送的脉冲数

实时速度反馈current_delay 随加速/减速段实时更新,匀速段等于目标速度
串口通信非阻塞输入轮询使用 select.poll,延时 1ms 检查串口,不阻塞电机脉冲输出

命令解析与容错支持大小写、别名,未知命令提示帮助

image.png

import machine
import utime
import select
import sys
import math

# ========== 引脚定义 ==========
motor_dir = machine.Pin(5, machine.Pin.OUT)   # 方向
motor_step = machine.Pin(4, machine.Pin.OUT)  # 脉冲
motor_en = machine.Pin(1, machine.Pin.OUT)    # 使能(低有效)

# ========== 梯形加减速参数 ==========
MIN_DELAY_US = 100      # 最高速度(最小间隔)
MAX_DELAY_US = 5000     # 最低速度(最大间隔)
START_DELAY_US = 2000   # 启动速度(较平缓起步)

ACCEL_STEPS = 800       # 加速段步数
DECEL_STEPS = 800       # 减速段步数

# ========== 状态变量 ==========
state = 'stop'          # 'stop', 'accel', 'run', 'decel'
current_delay = START_DELAY_US   # 当前实际速度
target_delay = START_DELAY_US    # 用户设定的目标速度
step_counter = 0        # 当前段内已走步数
total_steps = 0         # 总运行步数
direction = 1           # 1=正向, 0=反向
position = 0            # 当前位置

# ========== 初始化 ==========
motor_en.value(1)       # 初始禁用电机(高电平)
motor_dir.value(1)
motor_step.value(0)

poll = select.poll()
poll.register(sys.stdin, select.POLLIN)

print("=" * 50)
print("步进电机串口控制系统(梯形加减速)")
print("=" * 50)
print("命令列表:")
print("  s / start   : 启动(自动梯形加速)")
print("  x / stop    : 停止(自动梯形减速)")
print("  r / reverse : 反转方向(需先停止)")
print("  + / faster  : 提高目标速度")
print("  - / slower  : 降低目标速度")
print("  i / info    : 查看状态")
print("  h / help    : 显示帮助")
print("=" * 50)
print(f"速度范围: {MIN_DELAY_US}us(快) ~ {MAX_DELAY_US}us(慢)")
print(f"当前目标速度: {target_delay}us")

def show_status():
   dir_str = '正向' if direction else '反向'
   en_str = '使能' if motor_en.value() == 0 else '禁用'
   print(f"[状态] 运行: {state} | 方向: {dir_str}")
   print(f"       当前速度: {current_delay}us | 目标速度: {target_delay}us")
   print(f"       电机: {en_str} | 位置: {position}")

def parse_cmd(cmd_str):
   cmd = cmd_str.strip().lower()
   if cmd in ('s', 'start', 'go'):
       return 'start'
   elif cmd in ('x', 'stop', 'halt'):
       return 'stop'
   elif cmd in ('r', 'reverse', 'rev'):
       return 'reverse'
   elif cmd in ('+', 'faster', 'up'):
       return 'faster'
   elif cmd in ('-', 'slower', 'down'):
       return 'slower'
   elif cmd in ('i', 'info', 'status'):
       return 'info'
   elif cmd in ('h', 'help', '?'):
       return 'help'
   return None

def calculate_s_curve_delay(step, total_steps, start_d, end_d):
   """S曲线插值:从 start_d 单调变化到 end_d"""
   if total_steps == 0:
       return end_d
   ratio = min(1.0, step / total_steps)
   factor = math.sin(math.pi / 2 * ratio) ** 2
   return int(start_d + (end_d - start_d) * factor)

# ========== 主循环 ==========
while True:
   # ---- 检查串口输入 ----
   events = poll.poll(1)
   if events:
       try:
           line = sys.stdin.readline().strip()
           if not line:
               continue
           cmd = parse_cmd(line)
         
           if cmd == 'start':
               if state in ('run', 'accel'):
                   print("[提示] 电机已在运行中")
               else:
                   state = 'accel'
                   step_counter = 0
                   motor_dir.value(direction)
                   motor_en.value(0)          # 使能电机
                   print("[启动] 开始梯形加速...")
               show_status()
             
           elif cmd == 'stop':
               state = 'stop'                 # 关键:停止状态
               motor_en.value(1)              # 禁用电机(高电平)
               print("[提示] 电机已停止")
               show_status()
             
           elif cmd == 'reverse':
               if state != 'stop':
                   print("[错误] 请先停止电机再反转方向!")
               else:
                   direction = 0 if direction else 1
                   motor_dir.value(direction)
                   print(f"[反转] 方向: {'正向' if direction else '反向'}")
               show_status()
             
           elif cmd == 'faster':
               old = target_delay
               target_delay = max(MIN_DELAY_US, target_delay - 300)
               print(f"[加速] 目标: {old}us → {target_delay}us")
               # 如果电机正在运行,重新调整运动曲线
               if state == 'run':
                   state = 'accel'
                   step_counter = 0
                   print("       重新加速")
               elif state == 'decel':
                   state = 'accel'
                   step_counter = 0
                   print("       改为加速")
               show_status()
             
           elif cmd == 'slower':
               old = target_delay
               target_delay = min(MAX_DELAY_US, target_delay + 300)
               print(f"[减速] 目标: {old}us → {target_delay}us")
               if state == 'run':
                   state = 'decel'
                   step_counter = 0
                   print("       重新减速")
               elif state == 'accel':
                   state = 'decel'
                   step_counter = 0
                   print("       改为减速")
               show_status()
             
           elif cmd == 'info':
               show_status()
           elif cmd == 'help':
               print("命令: s/start, x/stop, r/reverse, +/faster, -/slower, i/info, h/help")
           else:
               print(f"[未知命令] '{line}',输入 h 查看帮助")
       except Exception as e:
           print(f"[错误] {e}")
 
   # ---- 电机驱动(S曲线加减速)----
   if state == 'stop':
       utime.sleep_ms(1)
       continue
 
   if motor_en.value() == 1:
       motor_en.value(0)   # 确保使能
 
   # 加速段
   if state == 'accel':
       current_delay = calculate_s_curve_delay(step_counter, ACCEL_STEPS, START_DELAY_US, target_delay)
       step_counter += 1
       if step_counter >= ACCEL_STEPS or abs(current_delay - target_delay) <= 1:
           state = 'run'
           step_counter = 0
           current_delay = target_delay
           print("[加速完成] 进入匀速")
           show_status()
         
   # 减速段(复用插值函数,从 target_delay 渐变到 START_DELAY_US)
   elif state == 'decel':
       current_delay = calculate_s_curve_delay(step_counter, DECEL_STEPS, target_delay, START_DELAY_US)
       step_counter += 1
       if step_counter >= DECEL_STEPS or abs(current_delay - START_DELAY_US) <= 1:
           state = 'run'
           step_counter = 0
           current_delay = target_delay
           print("[减速完成] 进入匀速")
           show_status()
           continue
         
   # 发送一个脉冲
   motor_step.value(1)
   utime.sleep_us(current_delay)
   motor_step.value(0)
   utime.sleep_us(current_delay)
 
   position += 1 if direction else -1
   total_steps += 1





关键词: 静音步进电机控制     成果帖    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]