在上一篇帖子中,我已经实现了Raspberry Pi Pico通过TMC2209控制NEMA17步进电机正反转控制,并实现了稳定平滑的电机转速和转向控制Let'sdo2026年第1期—电机转动实现-电子产品世界论坛,本文我将实现利用串口控制电机转动,主要新增以下功能
串口命令控制
实时启动/停止/释放电机
正转/反转/方向切换
慢速/快速切换
自定义STEP频率
自定义RPM转速
自定义加减速参数
非阻塞加减速
状态查询
新增库函数用于实现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)实现效果如下

完整工程代码如下
我要赚赏金
