这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sdo2026年第1期—串口控制电机运动

共2条 1/1 1 跳转至

Let'sdo2026年第1期—串口控制电机运动

工程师
2026-07-04 20:10:54     打赏

在上一篇帖子中,我已经实现了Raspberry Pi Pico通过TMC2209控制NEMA17步进电机正反转控制,并实现了稳定平滑的电机转速和转向控制Let'sdo2026年第1期—电机转动实现-电子产品世界论坛,本文我将实现利用串口控制电机转动,主要新增以下功能

  1. 串口命令控制

  2. 实时启动/停止/释放电机

  3. 正转/反转/方向切换

  4. 慢速/快速切换

  5. 自定义STEP频率

  6. 自定义RPM转速

  7. 自定义加减速参数

  8. 非阻塞加减速

  9. 状态查询

新增库函数用于实现USB串口读取用户输入的命令

import sys
import select

新增检测串口输入,防止阻塞程序

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

设计读取函数,用于在主循环中不断检查有没有新的串口命令

def read_serial_command():
    if poller.poll(0):
        return sys.stdin.readline()
    return None

新增电机状态变量

current_speed:当前实际STEP频率

target_speed:目标STEP频率

direction_cw:当前方向

motor_enabled:驱动器是否使能

motor_running:电机是否处于运行状态

新增了非阻塞式加减速,实现了每次只调整一步速度,然后马上返回主循环

def ramp_update_nonblocking():
    """
    非阻塞加减速。
    主循环中周期性调用,让串口命令仍然能响应。
    """
    global current_speed, target_speed

    if current_speed == target_speed:
        return

    if current_speed < target_speed:
        current_speed += ramp_step
        if current_speed > target_speed:
            current_speed = target_speed
    else:
        current_speed -= ramp_step
        if current_speed < target_speed:
            current_speed = target_speed

    if current_speed <= 0:
        stop_pwm_only()
    else:
        set_step_frequency(current_speed)

在主循环中周期性调用,这样电机在加速减速过程中,程序仍然可以继续接收串口命令

if time.ticks_diff(now, last_ramp_time) >= int(ramp_delay * 1000):
    ramp_update_nonblocking()
    last_ramp_time = now

新增串口命令功能,支持命令如下

start          启动电机
stop           减速停止,保持力矩
release        停止并关闭驱动,释放电机
cw             设置正转
ccw            设置反转
reverse        当前方向反转
slow           设置慢速
fast           设置快速
speed 1000     设置目标 STEP 频率为 1000 step/s
rpm 20         设置目标转速为 20 rpm
accel 40       设置加减速步进
status         查看当前状态
help           显示帮助

新增函数包括启动电机,如果驱动器未使能,则先使能TMC2209,设置当前方向,如果目标速度未0,则默认使用慢速,并设置morot_running=True

def start_motor():
    global motor_running, target_speed

    if not motor_enabled:
        enable_driver()

    apply_direction(direction_cw)

    if target_speed <= 0:
        target_speed = SLOW_SPEED

    motor_running = True
    print("Motor start, target speed =", target_speed, "step/s")

停止但保持力矩

def stop_motor_hold():
    """
    减速停止,但不关闭驱动,电机保持力矩。
    """
    global target_speed, motor_running

    print("Stopping motor and holding position")
    target_speed = 0
    ramp_to_speed_blocking(0)
    motor_running = False

停止并释放电机

def disable_driver():
    global motor_enabled, motor_running, target_speed

    target_speed = 0
    ramp_to_speed_blocking(0)
    time.sleep_ms(50)

    # 高电平关闭驱动,电机无保持力,可手动转动
    en_pin.value(1)
    motor_enabled = False
    motor_running = False

    print("Driver released")

切换方向,在切换方向过程中需要先减速到0,然后再反转恢复到目标转速

def set_direction_safe(clockwise):
    """
    安全切换方向:
    如果正在运行,先减速停止,再改 DIR,再恢复原速度。
    """
    global direction_cw, target_speed, motor_running

    old_target = target_speed

    if current_speed > 0:
        print("Decelerating before direction change")
        ramp_to_speed_blocking(0)
        time.sleep_ms(100)

    direction_cw = clockwise
    apply_direction(direction_cw)

    if motor_running and old_target > 0:
        target_speed = old_target
        print("Direction changed, restarting")
    else:
        target_speed = 0

    if direction_cw:
        print("Direction = CW")
    else:
        print("Direction = CCW")

设置目标速度

def set_target_speed(freq):
    global target_speed, motor_running

    freq = int(freq)
    if freq < 0:
        freq = 0

    target_speed = freq

    if freq > 0:
        if not motor_enabled:
            enable_driver()
        apply_direction(direction_cw)
        motor_running = True

    print("Target speed =", target_speed, "step/s, rpm =", step_freq_to_rpm(target_speed))

在主循环中,不断检查串口有无新的指令,同时周期性更新电机的运行状态,这样非阻塞的运行方式实现了电机在运行过程中也可以继续接收控制命令

def main():
    global target_speed

    # 默认关闭驱动,避免上电瞬间电机发热
    en_pin.value(1)
    stop_pwm_only()

    print("TMC2209 Pico Stepper Controller Ready")
    print_help()

    last_ramp_time = time.ticks_ms()

    while True:
        # 读取串口命令
        line = read_serial_command()
        if line is not None:
            handle_command(line)

        # 非阻塞加减速控制
        now = time.ticks_ms()
        if time.ticks_diff(now, last_ramp_time) >= int(ramp_delay * 1000):
            ramp_update_nonblocking()
            last_ramp_time = now

        time.sleep_ms(2)

实现效果如下

6d1368dd7c179b82d6e943ee4ea82973.gif

完整工程代码如下

uart_control.zip




关键词: uart     步进电机    

院士
2026-07-05 11:16:25     打赏
2楼

学习学习,谢谢分享。


共2条 1/1 1 跳转至

回复

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