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.
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")