1、TMC2209扩展板介绍
这块TMC2209扩展板的设计很简单,将TMC2209驱动模块与ATOMS3R-CAM主控连接,并补全独立供电与控制接口。
板上集成了DC电源输入插座与电源开关,预留了SPRD(展频)、MS1、MS2微步配置跳线,以及用于后续高级调试的UART串口接口。整体布局紧凑,在保证功能完整的前提下尽可能缩小了体积,方便与ATOMS3R-CAM堆叠使用。
原理图:

PCB图:

焊接后实物图:

2、ATOMS3R-CAM固件
使用M5Stack官方提供的M5Burner,为ATOMS3R-CAM烧录UIFlow2固件。

该固件同时支持图形化编程与MicroPython。本次测试采用MicroPython编写驱动代码,通过调节STEP引脚方波的频率来控制电机转速。
3、电机驱动测试
在上一篇内容中,我已实现对步进电机的基本控制,本次测试的重点是验证不同速度档位的运行控制。步进电机的线速度完全由脉冲频率决定,换算公式为:
频率(Hz)=目标速度(mm/s) / 每脉冲移动距离(mm/pulse)
以本次测试使用的电机为例,在8细分模式下,单脉冲对应位移约为0.00065mm。当设定max_speed=10时,对应的脉冲频率约为15.4kHz;设定max_speed=20时,频率升至约30.8kHz。
测试程序实现了基础的往复运动逻辑:先以较高速度单向移动到限位位置,再以较低速度匀速返回原点,以此验证驱动器在不同频率下的响应稳定性与加减速平滑度。
测试代码如下:
import os, sys, io
import M5
from M5 import *
from machine import Pin
import time
# ========== 硬件与运动参数配置 ==========
PIN_DIR = 7 # 方向引脚
PIN_STEP = 6 # 脉冲引脚
PIN_EN = 5 # 使能引脚(低有效)
MM_PER_PULSE = 0.0052 / 8 # 1/8微步下的单脉冲位移(mm)
START_SPEED = 1.0 # 起步安全速度(mm/s)
# ========== 全局状态变量 ==========
motor_dir = None
motor_step = None
motor_en = None
# 运动状态机
move_state = "IDLE" # IDLE / MOVING
total_pulses = 0
accel_pulses = 0
const_pulses = 0
pulse_index = 0
speed_step = 0
current_half_period_us = 0
last_pulse_time_us = 0
# 任务队列(按需添加多个移动指令)
move_queue = []
def _calc_move_params(distance_mm, max_speed, accel):
"""预计算梯形加减速的所有参数"""
global total_pulses, accel_pulses, const_pulses, speed_step, move_state
global pulse_index, current_half_period_us, last_pulse_time_us
if distance_mm == 0:
return False
# 设置方向
motor_dir.value(0 if distance_mm > 0 else 1)
distance_mm = abs(distance_mm)
total_pulses = int(distance_mm / MM_PER_PULSE)
if total_pulses == 0:
return False
# 计算加速段脉冲数 s = v²/(2a)
accel_dist = (max_speed ** 2) / (2 * accel)
accel_pulses = int(accel_dist / MM_PER_PULSE)
# 距离不足时退化为三角形速度曲线
if accel_pulses > total_pulses // 2:
accel_pulses = total_pulses // 2
const_pulses = total_pulses - 2 * accel_pulses
speed_step = (max_speed - START_SPEED) / accel_pulses if accel_pulses > 0 else 0
# 初始化运行状态
pulse_index = 0
current_half_period_us = int(1_000_000 / (START_SPEED / MM_PER_PULSE)) // 2
last_pulse_time_us = time.ticks_us()
move_state = "MOVING"
print(f"[TMC2209] 目标:{distance_mm}mm 总脉冲:{total_pulses} "
f"加速段:{accel_pulses} 匀速段:{const_pulses}")
return True
def _send_one_pulse():
"""非阻塞发送单个步进脉冲,返回True表示该次移动完成"""
global pulse_index, current_half_period_us, last_pulse_time_us, move_state
now = time.ticks_us()
elapsed = time.ticks_diff(now, last_pulse_time_us)
# 未到脉冲间隔时间,直接返回(让出CPU)
if elapsed < current_half_period_us * 2:
return False
# 发出一个完整脉冲
motor_step.value(1)
time.sleep_us(max(current_half_period_us, 30))
motor_step.value(0)
last_pulse_time_us = time.ticks_us()
# ---- 根据当前位置更新下一脉冲的速度 ----
pulse_index += 1
if pulse_index >= total_pulses:
move_state = "IDLE"
return True # 本次移动完成
# 计算当前应处速度
if pulse_index < accel_pulses:
spd = min(START_SPEED + pulse_index * speed_step,
START_SPEED + accel_pulses * speed_step)
elif pulse_index >= total_pulses - accel_pulses:
decel_i = total_pulses - pulse_index - 1
spd = max(START_SPEED + decel_i * speed_step, START_SPEED)
else:
spd = START_SPEED + accel_pulses * speed_step # 即 max_speed
freq = spd / MM_PER_PULSE
current_half_period_us = max(int(1_000_000 / freq) // 2, 30)
return False
def setup():
global motor_dir, motor_step, motor_en
M5.begin()
motor_dir = Pin(PIN_DIR, Pin.OUT)
motor_step = Pin(PIN_STEP, Pin.OUT)
motor_en = Pin(PIN_EN, Pin.OUT)
motor_en.value(0) # 使能驱动器
motor_step.value(0) # 脉冲默认低电平
# ====== 在此添加你的运动任务 ======
move_queue.append((30, 20.0, 80.0)) # 快速向外 30mm
move_queue.append((-30, 6.0, 20.0)) # 慢速返回 30mm
# ==================================
print("[TMC2209] 初始化完成,等待执行...")
def loop():
global move_queue
M5.update()
if move_state == "MOVING":
# 持续发送脉冲直到当前移动完成
if _send_one_pulse():
print("[TMC2209] 当前段移动完成")
time.sleep_ms(200) # 段间停顿(对应原代码的 utime.sleep_ms(200))
elif move_queue:
# 当前空闲且队列中有任务,取出下一个执行
dist, spd, acc = move_queue.pop(0)
_calc_move_params(dist, spd, acc)
else:
# 所有任务执行完毕,安全禁用电机
motor_en.value(1)
# 防止loop空转消耗CPU
time.sleep_ms(10)
if __name__ == '__main__':
try:
setup()
while True:
loop()
except (Exception, KeyboardInterrupt) as e:
try:
motor_en.value(1)
print("[TMC2209] 异常中断,电机已安全禁用")
except Exception:
pass
try:
from utility import print_error_msg
print_error_msg(e)
except ImportError:
print("please update to latest firmware")
我要赚赏金
