StallGuard - Chr157i4n/PyTmcStepper GitHub Wiki

StallGuard

The TMC2209 driver has the capability to measure the motor load. This can be used to detect stalls during movement or to perform a sensorless homing.

grafik

How to use StallGuard

The driver calculates the StallGuard result (SG_RESULT; 0 - 510) internally and compares this with the double of the StallGuard threshold (SGTHRS; 0 - 255). You can get the StallGuard result with this function:

get_stallguard_result()

and you can set the StallGuard threshold with this function:

set_stallguard_threshold(threshold)

When the driver detects a stall (SG_RESULT < 2* SGTHRS), the DIAG pin is pulsed. Inside this library there is a function which can be used to attach a userdefined callback function to StallGuard via interrupt on a Raspberry Pi pin which should be connected to the DIAG pin of the TMC2209:

set_stallguard_callback(pin_stallguard, threshold, callback)

StallGuard only works in StealthChop mode and above the speed of TCOOLTHRS (TCOOLTHRS ≥ TSTEP > TPWMTHRS), this can be set with the function:

set_coolstep_threshold(threshold)

because TCOOLTHRS is compared to TSTEP which is the time for 1/256 microstep (1 - 2^20-1) the set_stallguard_callback function has a parameter min_speed which internally calculates the TCOOLTHRS for a given velocity in steps/seconds. Just like set_max_speed(speed). The min_speed for StallGuard should be set the value slightly lower than your max_speed (like 800/1000) to prevent StallGuard from triggering while accelerating.

StallGuard tuning

The datasheet has a chapter (11.2 Tuning StallGuard4; page 59) which describes the procedure to tune StallGuard for your setup: Monitoring the SG_Result value can be done with this function:

test_stallguard_threshold(self, steps)

It prints the current movement phase (accel, max_speed or decel) and the current SG_Result. Note that this is not synchronised with each step.

StallGuard demo

There are already some videos about Stallguard: https://www.youtube.com/watch?v=TEkM0uLlkHU

The 3D-printing files for that are available here: https://www.printables.com/model/1332530-sensorless-homing-in-python-rp2040-tmc2209

You can use the following code for that demo. The motor is first moved 1 Revolution (-200 Steps) backwards. If this movement is completed without interruption the message "Endstop 1 not found" is being printed and the scripts ends. To actually find the Endstops and stop there, the callback function "my_callback" is assigned to StallGuard on Pin 16 with the threshold 50. If the driver detect a Stall/Endstop my_callback is being called and the movement stops immediatly. The main-thread detects this by reading the return value of run_to_position_fullsteps. After both Endstop where found, the script calculates the middle and moves to it.

def my_callback():
    """StallGuard callback"""
    tmc.tmc_mc.stop()


tmc.set_stallguard_callback(
    16, 50, my_callback
)


result = tmc.run_to_position_fullsteps(-200, MovementAbsRel.RELATIVE)

if result is StopMode.HARDSTOP:
    print("Endstop 1 found")
    tmc.current_pos_fullstep = 0  # reset position to 0

    result = tmc.run_to_position_fullsteps(200, MovementAbsRel.RELATIVE)

    if result is StopMode.HARDSTOP:
        print("Endstop 2 found")

        middle = tmc.current_pos_fullstep // 2
        tmc.run_to_position_fullsteps(middle, MovementAbsRel.ABSOLUTE)

    else:
        print("Endstop 2 not found")

else:
    print("Endstop 1 not found")

Alternatively, the following script, which uses do_homing, can also be used:

result = tmc.do_homing(
    diag_pin=16,
    revolutions=-1,
    threshold=50,
)

if result:
    print("Endstop 1 found")
    tmc.current_pos_fullstep = 0  # reset position to 0

    result = tmc.do_homing(
        diag_pin=16,
        revolutions=1,
        threshold=50,
        cb_success=None,
    )

    if result:
        print("Endstop 2 found")

        middle = tmc.current_pos_fullstep // 2
        tmc.run_to_position_fullsteps(middle, MovementAbsRel.ABSOLUTE)

    else:
        print("Endstop 2 not found")

else:
    print("Endstop 1 not found")