MaixPy tmc2209 单串口驱动使用介绍

更新历史
日期 版本 作者 更新内容
2024-08-21 1.0.0 iawak9lkm 初版文档

TMC2209 简介

TMC2209是一款由德国Trinamic公司生产的步进电机驱动芯片。它专为2相步进电机设计,具有低功耗、高效率和良好的噪声抑制能力。TMC2209支持高达2.8A的电流,适用于各种步进电机应用,如3D打印机、CNC机床、机器人等。

MaixPy 中使用 tmc2209 驱动步进电机

  • 请确保您的步进电机为两相四线步进电机, 然后确认您的电机步进角度(step_angle), 需要使用的微步数(micro_step), 以及该电机旋转一圈时, 负载移动的距离(screw_pitch或round_mm). 以便我们后续配置驱动参数.

  • 一般来说, 市面上的 TMC2209 的驱动板有以下这些引脚(如果您嫌麻烦, 可以采购我司在售的 TMC2209 驱动板, 链接[暂未上架,敬请期待]):

            ---------
         EN-|       |-VM
        MS1-|       |-GND
        MS2-|       |-2B
         RX-|       |-2A
         TX-|       |-1A
         NC-|       |-1B
       STEP-|       |-VDD
        DIR-|       |-GND
            ---------
    

    EN: EN 为使能脚, 将该引脚接到 GND 以硬件使能 TMC2209.

    MS1: MS1 为微步进选择引脚之一,与 MS2 引脚配合使用,用于设置步进电机的微步进模式。

    MS2: MS2 为微步进选择引脚之一,与 MS1 引脚配合使用,用于设置步进电机的微步进模式。

    This driver program only supports the UART mode of TMC2209. In UART mode, the original microstep selection pins MS1 and MS2 are redefined as AD0 and AD1, respectively. The combination of the logic levels of these two pins determines the UART address of the TMC2209, with a value range from 0x00 to 0x03. This means that a single UART port can connect up to 4 TMC2209 drivers with different addresses. For example, when MS1 is at a low level (0) and MS2 is at a high level (1), the UART address is binary 0b10, which is hexadecimal 0x02.

    TX: TX 为串行通信发送引脚,用于与外部微控制器进行串口通信。

    RX: RX 为串行通信接收引脚,用于与外部微控制器进行串口通信。

    在 TMC2209 上, 同时使用 RXTX 时, 请确保 TMC2209 驱动板 RX 与主控芯片 TX 间存在 1K 欧姆的电阻. 否则会出现通信数据异常.

    NC: NC 为未连接引脚,表示该引脚在正常使用中不需要连接。

    STEP: STEP 为步进信号输入引脚,每接收到一个脉冲信号,步进电机前进一个步进角度。因为本驱动为纯 UART 方式驱动,故该引脚不需要连接, 悬空即可.

    DIR: DIR 为方向信号输入引脚,用于控制步进电机的旋转方向。当 DIR 为高电平时,电机顺时针旋转;当 DIR 为低电平时,电机逆时针旋转。因为本驱动为纯 UART 方式驱动,故该引脚不需要连接, 悬空即可.

    VM: VM 为电源输入引脚,连接到步进电机的电源正极。

    GND: GND 为接地引脚,连接到电源的负极。

    2B, 2A, 1B, 1A: 这些引脚为步进电机的相位输出引脚,分别连接到步进电机的两相线圈。

    VDD: VDD 为逻辑电源输入引脚,为芯片内部的逻辑电路提供电源。

  • 使用 MaixPy 中的 TMC2209 驱动

以一个步进角度为18,微步数为256,螺距为3mm的丝杆步进电机为例:

from maix import pinmap, ext_dev, err, time

port = "/dev/ttyS1"
uart_addr = 0x00
uart_baudrate = 115200
step_angle = 18
micro_step = 256
screw_pitch = 3
speed = 6
use_internal_sense_resistors = True
run_current_per = 100
hold_current_per = 100


if port == "/dev/ttyS1":
    ret = pinmap.set_pin_function("A19", "UART1_TX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)
    ret = pinmap.set_pin_function("A18", "UART1_RX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)

slide = ext_dev.tmc2209.ScrewSlide(port, uart_addr, uart_baudrate,
                            step_angle, micro_step, screw_pitch, speed,
                            use_internal_sense_resistors, run_current_per, hold_current_per)

def reset_callback() -> bool:
    if 2 > 1:   # An event occurs (e.g., a sensor is triggered),
                # indicating that the slide has moved to the boundary and the motor needs to stop.
        print("Reset finish...")
        return True
    # Not occurred, no need to stop the motor.
    return False

def move_callback(per:float) -> bool:
    # per is the percentage of the current distance moved by move()
    # out of the total distance required for the current move(), ranging from 0 to 100.
    print(f"Slide moving... {per}")
    if per >= 50: # Example: Stop moving when 50% of the total distance for the current move() has been covered.
        print(f"{per} >= 50%, stop.")
        return True
    return False


slide.reset(reset_callback)

slide.move(screw_pitch*2, -1, move_callback)
slide.move(-screw_pitch)

while True:
    slide.move(screw_pitch*2)
    slide.move(-(screw_pitch*2))
    time.sleep_ms(100)

程序中需要先使用 pinmap 确保 UART1 被启用.

然后创建一个 ScrewSlide 对象, 默认使用内部参考电阻, 默认使用 100% 的电机运行电流和 100% 的电机保持电流. 这些参数可能需要根据您的电机进行调整.

然后例程声明了一个reset回调函数和一个move回调函数并分别传入reset()函数和move()函数中. reset() 和 move() 会每隔一段时间调用回调函数以确认是否需要立即停止电机(当回调函数返回True).

move() 和 reset() 函数均为阻塞函数, 只有在回调函数返回True时(move还能在运动完指定长度时)停止电机并返回.

MaixPy 中使用 tmc2209 驱动恒定负载的步进电机

!!!丝杆步进电机携带恒定负载也不能视为带恒定负载的步进电机, 因为丝杆步进电机有限位装置以保证负载在杠上的运动方向是可知的, 丝杆步进电机运行时会与限位装置经常碰撞导致电机负载并不是恒定的. 其他情况举一反三即可知是否为恒定负载步进电机.

某些应用场景中, 步进电机全程的负载恒定, 只有在接触到边缘堵转时负载变高. 那么可以使用 Slide 类代替 ScrewSlide 类, 在这种情况下 Slide 具备堵转检测功能. 使用 ScrewSlide 也是可行的, 不具备堵转检测但是更加灵活. 请结合使用场景来选择这两个类, 本节只讲 Slide 类.

  • 实现原理

TMC2209 内部存在一个寄存器 SG_RESULT, 该寄存器保存的数据与驱动电机剩余力矩成正比. 如果电机负载恒定, 该寄存器值变化幅度很小, 在堵转时, 该寄存器值将会快速减小并维持一个较低的值. 找到该恒定负载电机这个寄存器的运行平均值和堵转平均值, 即可衡量该电机在某时刻是否堵转.

  • 获取 SG_RESULT 寄存器的平均值

maix.ext_dev.tmc2209 中提供了获取并保存该平均值的函数 maix.ext_dev.tmc2209.slide_scan.

example:

from maix import ext_dev, pinmap, err

port = "/dev/ttyS1"
uart_addr = 0x00
uart_baudrate = 115200
step_angle = 1.8
micro_step = 256
round_mm = 60
speed = 60
use_internal_sense_resistors = True
run_current_per = 100
hold_current_per = 100

if port == "/dev/ttyS1":
    ret = pinmap.set_pin_function("A19", "UART1_TX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)
    ret = pinmap.set_pin_function("A18", "UART1_RX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)

ext_dev.tmc2209.slide_scan(port, uart_addr, uart_baudrate,
                           step_angle, micro_step, round_mm, speed, True,
                           True, run_current_per, hold_current_per,
                           conf_save_path='./slide_scan_example.bin', force_update=False)

配置好串口和驱动器参数, 然后调用 slide_scan. slide_scan 的最后一个参数 force_update 决定了在该配置文件已经存在时的行为:

如果 force_update 为 True, 将会用新的配置覆盖旧的配置

如果 force_update 为 False, 运行平均值将会更新为新旧值的平均值, 堵转平均值将会更新成新旧堵转平均值中较大的那一个值(例如一个滑胎有左右边界, 左边界堵转平均值小于右边界堵转平均值, 也就是说右边界比左边界更容易堵转, 保存最容易堵转的平均值).

该程序执行后, 步进电机会一直保持正向旋转, 当遇到堵转时, 稍等300ms左右, 停止该程序. 程序会记录运行时的 SG_RESULT 寄存器平均值和堵转时的寄存器平均值到 conf_save_path 中.

后续 Slide 类可以加载该配置文件实现堵转时停止电机.

  • 验证配置文件的值

或许您会好奇这个配置到底能不能用. maix.ext_dev.tmc2209 提供了测试该配置文件的函数 slide_test.

先保证电机微处于堵转状态, 然后修改参数以匹配您调用 slide_scan 的参数, 执行以下代码.

example

from maix import ext_dev, pinmap, err

port = "/dev/ttyS1"
uart_addr = 0x00
uart_baudrate = 115200
step_angle = 1.8
micro_step = 256
round_mm = 60
speed = 60
use_internal_sense_resistors = True
run_current_per = 100
hold_current_per = 100

if port == "/dev/ttyS1":
    ret = pinmap.set_pin_function("A19", "UART1_TX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)
    ret = pinmap.set_pin_function("A18", "UART1_RX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)

ext_dev.tmc2209.slide_test(port, uart_addr, uart_baudrate,
                           step_angle, micro_step, round_mm, speed, True,
                           True, run_current_per, hold_current_per,
                           conf_save_path='./slide_scan_example.bin')

电机将会在堵转瞬间停止转动, 程序也会随之结束.

Slide.move()Slide.reset() 堵转停止逻辑也是如此.

  • 使用 Slide

使用 Slide 的思路与 ScrewSlide 基本无异, 只是 Slide 取消了回调函数并增加了堵转停止逻辑.

如果使用 Slide 时未传入配置文件, Slide也是可以使用的. 堵转检测阈值为电机运行开始时的平均数*Slide.stop_default_per()/100. 电机运行近期平均数低于该值时电机停止. 可以通过 Slide.stop_default_per() 获取和修改该值.

from maix import pinmap, ext_dev, err, time

port = "/dev/ttyS1"
uart_addr = 0x00
uart_baudrate = 115200
step_angle = 1.8
micro_step = 256
round_mm = 60
speed = 60
use_internal_sense_resistors = True
run_current_per = 100
hold_current_per = 100

if port == "/dev/ttyS1":
    ret = pinmap.set_pin_function("A19", "UART1_TX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)
    ret = pinmap.set_pin_function("A18", "UART1_RX")
    if ret != err.Err.ERR_NONE:
        print("Failed in function pinmap...")
        exit(-1)

slide = ext_dev.tmc2209.Slide(port, uart_addr, uart_baudrate,
                              step_angle, micro_step, round_mm, speed,
                              cfg_file_path="./slide_conf.bin")

slide.reset()
slide.move(60)
slide.move(-60)

注意事项

本驱动程序由纯串口实现, 优点是占有引脚占用引脚较少即可实现至多4个较高精度的电机驱动. 缺点是不适用于高精度要求的应用场景.

已知问题:

  • 请勿使用 MaixCAM 的 UART0 作为驱动串口, 会导致 MaixCAM 无法正常开机等问题.

!!!如有BUG, 非常欢迎您提交 PR 反馈.

免责声明

本电机驱动程序(以下简称“程序”)是由[Sipeed]基于BSD-3开源协议的仓库 janelia-arduino/TMC2209 进行修改和使用的。本程序仅供学习和研究使用,不保证在所有环境和条件下都能正常工作。使用本程序的风险由用户自行承担。

[Sipeed]不对因使用或无法使用本程序而导致的任何损失或损害承担责任,包括但不限于直接损失、间接损失、偶然损失、特殊损失、惩罚性损失或后果性损失。

用户在实际应用中使用本程序前,应自行进行充分的测试和验证,确保程序符合其特定需求和环境。[Sipeed]不对程序的准确性、可靠性、完整性或适用性做出任何明示或暗示的保证。

用户在使用本程序时应遵守所有适用的法律法规,并确保不侵犯任何第三方的合法权益。[Sipeed]不对因用户违反法律法规或侵犯第三方权益而导致的任何后果承担责任。

本免责声明的解释权归[Sipeed]所有,并保留随时修改本免责声明的权利。