Skip to content

Commit f6d01bb

Browse files
authored
Merge pull request #524 from ArmoredTurtle/DEV for Release v1.0.29
Release v1.0.29
2 parents 9c7f672 + 6d71ea3 commit f6d01bb

27 files changed

+643
-140
lines changed

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2025-08-30]
9+
### Added
10+
- Catch for JSON decode error when trying to read and load AFC.var.unit file
11+
12+
### Fixes
13+
- Issue where TMC section search would error out if not defined. Search is now gated behind user enabling print_current variable. If a user is using a different driver, like a4988 for example, AFC will not error out as long as print_current variable is not defined.
14+
15+
## [2025-08-24]
16+
### Added
17+
- You can now use the `install-afc.sh` script to delete the `AFC.var.unit` file if necessary. This option is located under
18+
the `Utilities` menu.
19+
20+
### Fixed
21+
- Issue where HTLF unit would not select lane and sync with extruder when running prep
22+
23+
## [2025-08-22]
24+
### Added
25+
- Added a new command to test lane loading and unloading in an automated and random fashion (`AFC_TEST_LANES`). Please
26+
see the documentation for more information on how to use this command and it's various options.
27+
- Option to delay/debounce switches. Debounce delay is defaulted to zero but can be updated globally by adding `debounce_delay: <delay_value>`
28+
to AFC config section. Or this value can be added per AFC_extruder, AFC_hub, AFC_stepper/AFC_lane configs. Runout can be also disabled by
29+
turning off filament switch in gui, if PREP sensor is disabled this will also disable infinite spool rollover. When klipper is restarted
30+
all switches will be enabled again.
31+
32+
## [2025-08-17]
33+
### Added
34+
- Servo option to brush macro.
35+
36+
## [2025-08-10]
37+
### Fixed
38+
- A negative `afc_unload_bowden_length` is no longer able to be set by the calibration routine.
39+
40+
## [2025-08-06]
41+
### Fixed
42+
- The `install-afc.sh` script will no longer tell you it removed the `velocity` setting if it didn't exist.
43+
44+
## [2025-07-30]
45+
### Fixed
46+
- Updated the `SET_MAP` command to correctly handle `MAP` parameters in either upper or lower case text.
47+
48+
## [2025-07-27]
49+
### Updated
50+
- The `install-afc.sh` script will now only copy relevant MCU files when installing a new unit.
51+
852
## [2025-07-20]
953
### Added
1054
- Software defined physical buttons are now available and supported. See documentation for more information on how to set them up.

config/AFC_Macro_Vars.cfg

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ variable_cut_accel : 0
3838
variable_cut_direction : "left"
3939

4040
# This distance is used to move toolhead to cut filament
41-
# and to create a small saftely distance that aids in generating momentum
41+
# and to create a small safety distance that aids in generating momentum
4242
variable_pin_park_dist : 6.0 # Distance in mm
4343

4444
# Position of the toolhead when the cutter is fully compressed.
@@ -93,7 +93,7 @@ variable_pushback_dwell_time : 20 # Time to dwell between the pushba
9393
variable_safe_margin_xy : 30, 30 # Approx toolhead width +5mm, height +5mm)
9494

9595
# Some printers may need a boost of power to complete the cut without skipping steps.
96-
# One option is to increase the current for thost steppers in printer.cfg. Another
96+
# One option is to increase the current for the steppers in printer.cfg. Another
9797
# option is to use these variables to set a current that is only used during the
9898
# cut motion. Different combinations of kinematics and cutter configurations engage
9999
# different combinations of steppers for that motion. Set the needed variables.
@@ -208,6 +208,12 @@ variable_brush_count : 4 # Number of passes to make on the
208208
# Move in Z after brush to avoid bed if brush is at Z0 (Set z to -1 if you dont want a z move)
209209
variable_z_move : -1
210210

211+
# Addon variables for brush servo control
212+
#variable_tool_servo_enable : False
213+
#variable_tool_servo_name : "tool_brush"
214+
#variable_tool_servo_angle_out : 115
215+
#variable_tool_servo_angle_in : 0
216+
211217

212218
#--=================================================================================-
213219
#------- Park ----------------------------------------------------------------------
@@ -221,4 +227,4 @@ variable_park_loc_xy : -1, -1 # Position to park the toolhead
221227
variable_z_hop : 0 # Height to raise Z when moving to park. Leave 0 to disable
222228
variable_park_z : 0 # Absolute height to lower to after park move. Leave 0 to disable
223229
# This is intended to be used to reduce oozing during loading / unload right before a poop.
224-
# Typically this would be set at the variable_purge_start value when needed.
230+
# Typically this would be set at the variable_purge_start value when needed.

config/macros/Brush.cfg

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ gcode:
1515
{% set brush_depth = vars['brush_depth'] | default(10) | float %}
1616
{% set brush_count = vars['brush_count'] | default(4) | int %}
1717
{% set z_move = vars['z_move'] | default(-1) | float %}
18+
{% set tool_servo_enable = vars['tool_servo_enable']|default(false) | lower == 'true' %}
1819

1920
# Get printer bounds to make sure none of our cleaning moves fall outside of them
2021
# Check for IDEX
@@ -56,6 +57,15 @@ gcode:
5657

5758
SET_VELOCITY_LIMIT ACCEL={selected_accel}
5859

60+
# Extend servo if enabled
61+
{% if tool_servo_enable %}
62+
{% if verbose > 1 %}
63+
RESPOND TYPE=command MSG='Brush Servo Extended'
64+
{% endif %}
65+
# Extend brush servo
66+
_BRUSH_SERVO POS=out
67+
{% endif %}
68+
5969
{% if verbose > 0 %}
6070
RESPOND TYPE=command MSG='AFC_Brush: Clean Nozzle'
6171
{% endif %}
@@ -121,7 +131,36 @@ gcode:
121131

122132
G90
123133

134+
# Retract servo if enabled
135+
{% if tool_servo_enable %}
136+
{% if verbose > 1 %}
137+
RESPOND TYPE=command MSG='Brush Servo Retracted'
138+
{% endif %}
139+
# Retract brush servo
140+
_BRUSH_SERVO POS=in
141+
{% endif %}
142+
124143
# Reset acceleration values to what it was before
125144
SET_VELOCITY_LIMIT ACCEL={saved_accel}
126145

127146
AFC_ENABLE_SKEW
147+
148+
#--=================================================================================-
149+
#------- Helper macro for brush servo -----------------------------------------------
150+
#--=================================================================================-
151+
[gcode_macro _BRUSH_SERVO]
152+
# Increase this value (in milliseconds) if the servo doesn't have enough time to fully retract or extend
153+
variable_dwell_time: 200
154+
gcode:
155+
{% set c1 = printer['gcode_macro _AFC_BRUSH_VARS'] %}
156+
{% set pos = params.POS %}
157+
{% if pos == "in" %}
158+
SET_SERVO SERVO={c1.tool_servo_name} ANGLE={c1.tool_servo_angle_in}
159+
G4 P{dwell_time}
160+
{% elif pos == "out" %}
161+
SET_SERVO SERVO={c1.tool_servo_name} ANGLE={c1.tool_servo_angle_out}
162+
G4 P{dwell_time}
163+
{% else %}
164+
{action_respond_info("Brush Servo: provide POS=[in|out]")}
165+
{% endif %}
166+
SET_SERVO SERVO={c1.tool_servo_name} WIDTH=0

extras/AFC.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
try: from extras.AFC_stats import AFCStats
2828
except: raise error(ERROR_STR.format(import_lib="AFC_stats", trace=traceback.format_exc()))
2929

30-
AFC_VERSION="1.0.26"
30+
AFC_VERSION="1.0.29"
3131

3232
# Class for holding different states so its clear what all valid states are
3333
class State:
@@ -121,10 +121,11 @@ def __init__(self, config):
121121
self.common_density_values = config.getlists("common_density_values",
122122
("PLA:1.24", "PETG:1.23", "ABS:1.04", "ASA:1.07"))
123123
self.common_density_values = list(self.common_density_values)
124+
self.test_extrude_amt = config.get('test_extrude_amt', 10)
124125

125126
#LED SETTINGS
126127
self.ind_lights = None
127-
# led_name is not used, either use or needs to be removed, removing this would break everyones config as well
128+
# led_name is not used, either use or needs to be removed, removing this would break everyone's config as well
128129
self.led_name = config.get('led_name',None)
129130
self.led_off = "0,0,0,0"
130131
self.led_fault = config.get('led_fault','1,0,0,0') # LED color to set when faults occur in lane (R,G,B,W) 0 = off, 1 = full brightness.
@@ -195,6 +196,9 @@ def __init__(self, config):
195196
self.enable_assist = config.getboolean("enable_assist", True)
196197
# Weight spool has to be below to activate print assist
197198
self.enable_assist_weight = config.getfloat("enable_assist_weight", 500.0)
199+
self.enable_hub_runout = config.getboolean("enable_hub_runout", True)
200+
self.enable_tool_runout = config.getboolean("enable_tool_runout", True)
201+
self.debounce_delay = config.getfloat("debounce_delay", 0.)
198202

199203
self.debug = config.getboolean('debug', False) # Setting to True turns on more debugging to show on console
200204
self.testing = config.getboolean('testing', False) # Set to true for testing only so that failure states can be tested without stats being reset
@@ -248,8 +252,8 @@ def _update_trsync(self, config):
248252
if update_trsync:
249253
try:
250254
import mcu
251-
trsync_value = config.getfloat("trsync_timeout", 0.05) # Timeout value to update in klipper mcu. Klippers default value is 0.025
252-
trsync_single_value = config.getfloat("trsync_single_timeout", 0.5) # Single timeout value to update in klipper mcu. Klippers default value is 0.250
255+
trsync_value = config.getfloat("trsync_timeout", 0.05) # Timeout value to update in klipper mcu. Klipper's default value is 0.025
256+
trsync_single_value = config.getfloat("trsync_single_timeout", 0.5) # Single timeout value to update in klipper mcu. Klipper's default value is 0.250
253257
self.logger.info("Applying TRSYNC update")
254258

255259
# Making sure value exists as kalico(danger klipper) does not have TRSYNC_TIMEOUT value
@@ -309,10 +313,10 @@ def handle_connect(self):
309313
try:
310314
self.bypass = self.printer.lookup_object('filament_switch_sensor bypass').runout_helper
311315
except:
312-
self.bypass = add_filament_switch("filament_switch_sensor virtual_bypass", "afc_virtual_bypass:virtual_bypass", self.printer ).runout_helper
316+
self.bypass = add_filament_switch("virtual_bypass", "afc_virtual_bypass:virtual_bypass", self.printer ).runout_helper
313317

314318
if self.show_quiet_mode:
315-
self.quiet_switch = add_filament_switch("filament_switch_sensor quiet_mode", "afc_quiet_mode:afc_quiet_mode", self.printer ).runout_helper
319+
self.quiet_switch = add_filament_switch("quiet_mode", "afc_quiet_mode:afc_quiet_mode", self.printer ).runout_helper
316320

317321
# Register G-Code commands for macros we don't want to show up in mainsail/fluidd
318322
self.gcode.register_command('TOOL_UNLOAD', self.cmd_TOOL_UNLOAD, desc=self.cmd_TOOL_UNLOAD_help)
@@ -378,7 +382,7 @@ def _get_default_material_temps(self, cur_lane):
378382
in AFC.cfg and sees if a temperature exists for filament material.
379383
380384
:param cur_lane: Current lane object
381-
:return truple : float for temperature to heat extruder to,
385+
:return tuple : float for temperature to heat extruder to,
382386
bool True if user is using min_extruder_temp value
383387
"""
384388
try:
@@ -1488,7 +1492,6 @@ def cmd_CHANGE_TOOL(self, gcmd):
14881492
CHANGE_TOOL LANE=lane1 PURGE_LENGTH=100
14891493
```
14901494
"""
1491-
self.afcDeltaTime.set_start_time()
14921495
# Check if the bypass filament sensor detects filament; if so, abort the tool change.
14931496
if self._check_bypass(unload=False): return
14941497

@@ -1530,6 +1533,7 @@ def cmd_CHANGE_TOOL(self, gcmd):
15301533
self.CHANGE_TOOL(self.lanes[self.tool_cmds[Tcmd]], purge_length)
15311534

15321535
def CHANGE_TOOL(self, cur_lane, purge_length=None, restore_pos=True):
1536+
self.afcDeltaTime.set_start_time()
15331537
# Check if the bypass filament sensor detects filament; if so, abort the tool change.
15341538
if self._check_bypass(unload=False): return
15351539

extras/AFC_BoxTurtle.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def calibrate_bowden(self, cur_lane, dis, tol):
123123
cur_lane.short_move_dis, 0, cur_lane.dist_hub + 200, "Moving to hub")
124124

125125
if not success:
126-
# if movement does not suceed fault and return values to calibration macro
126+
# if movement does not succeed fault and return values to calibration macro
127127
msg = 'Failed {} after {}mm'.format(checkpoint, hub_pos)
128128
return False, msg, hub_pos
129129

@@ -170,26 +170,27 @@ def calibrate_bowden(self, cur_lane, dis, tol):
170170
else:
171171
bowden_dist = bow_pos - cur_lane.short_move_dis
172172

173-
# Checking if user has set a custom unload length and adding the delta to the new
174-
# calibrated bowden distance
175-
if cur_lane.hub_obj.afc_unload_bowden_length != cur_lane.hub_obj.afc_bowden_length:
176-
unload_delta = cur_lane.hub_obj.afc_unload_bowden_length - cur_lane.hub_obj.afc_bowden_length
177-
unload_new = bowden_dist + unload_delta
178-
else:
179-
unload_new = bowden_dist
173+
unload_dist = bowden_dist
180174

181175
cal_msg = '\n afc_bowden_length: New: {} Old: {}'.format(bowden_dist, cur_lane.hub_obj.afc_bowden_length)
182-
unload_cal_msg = '\n afc_unload_bowden_length: New: {} Old: {}'.format(unload_new, cur_lane.hub_obj.afc_unload_bowden_length)
176+
unload_cal_msg = '\n afc_unload_bowden_length: New: {} Old: {}'.format(unload_dist, cur_lane.hub_obj.afc_unload_bowden_length)
183177
cur_lane.hub_obj.afc_bowden_length = bowden_dist
184-
cur_lane.hub_obj.afc_unload_bowden_length = unload_new
178+
cur_lane.hub_obj.afc_unload_bowden_length = unload_dist
185179

186180
if bowden_dist < 0:
187181
self.afc.error.AFC_error(
188182
"'{}' is not a valid length. Please check your setup and re-run calibration.".format(bowden_dist),
189183
pause=False)
190184
return False, "Invalid bowden length", bowden_dist
185+
186+
if unload_dist < 0:
187+
self.afc.error.AFC_error(
188+
"'{}' is not a valid unload length. Please check your setup and re-run calibration.".format(unload_dist),
189+
pause=False)
190+
return False, "Invalid unload bowden length", unload_dist
191+
191192
self.afc.function.ConfigRewrite(cur_hub.fullname, "afc_bowden_length", bowden_dist, cal_msg)
192-
self.afc.function.ConfigRewrite(cur_hub.fullname, "afc_unload_bowden_length", unload_new, unload_cal_msg)
193+
self.afc.function.ConfigRewrite(cur_hub.fullname, "afc_unload_bowden_length", unload_dist, unload_cal_msg)
193194
cur_lane.loaded_to_hub = True
194195
cur_lane.do_enable(False)
195196
self.afc.save_vars()
@@ -228,7 +229,7 @@ def calibrate_hub(self, cur_lane, tol):
228229
return True, msg, tuned_hub_pos
229230

230231
def move_until_state(self, cur_lane, state, move_dis, tolerance, short_move, pos=0, fault_dis=250, checkpoint=None):
231-
# moves filament until specified sensor, returns values for further czlibration
232+
# moves filament until specified sensor, returns values for further calibration
232233
while not state():
233234
cur_lane.move(move_dis, cur_lane.short_moves_speed, cur_lane.short_moves_accel)
234235
pos += move_dis

extras/AFC_HTLF.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def __init__(self, config):
3131
self.current_selected_lane = None
3232
self.home_state = False
3333
self.mm_move_per_rotation = config.getint("mm_move_per_rotation", 32) # How many mm moves pulley a full rotation
34-
self.cam_angle = config.getint("cam_angle") # CAM lobe angle thats currently installed. 30,45,60 (recommend using 60)
34+
self.cam_angle = config.getint("cam_angle") # CAM lobe angle that is currently installed. 30,45,60 (recommend using 60)
3535
self.home_pin = config.get("home_pin") # Pin for homing sensor
3636
self.MAX_ANGLE_MOVEMENT = config.getint("MAX_ANGLE_MOVEMENT", 215) # Max angle to move lobes, this is when lobe 1 is fully engaged with its lane
3737
self.enable_sensors_in_gui = config.getboolean("enable_sensors_in_gui", self.afc.enable_sensors_in_gui) # Set to True to show prep and load sensors switches as filament sensors in mainsail/fluidd gui, overrides value set in AFC.cfg
@@ -47,10 +47,8 @@ def __init__(self, config):
4747
buttons = self.printer.load_object(config, "buttons")
4848
buttons.register_buttons([self.home_pin], self.home_callback)
4949

50-
if self.enable_sensors_in_gui:
51-
if self.home_pin is not None:
52-
self.home_filament_switch_name = "filament_switch_sensor {}_home_pin".format(self.name)
53-
self.home_sensor = add_filament_switch(self.home_filament_switch_name, self.home_pin, self.printer )
50+
if self.home_pin is not None:
51+
self.home_sensor = add_filament_switch(f"{self.name}_home_pin", self.home_pin, self.printer, self.enable_sensors_in_gui )
5452

5553
def handle_connect(self):
5654
"""
@@ -85,6 +83,7 @@ def system_Test(self, cur_lane, delay, assignTcmd, enable_movement):
8583
if not self.prep_homed:
8684
self.return_to_home( prep = True)
8785
status = super().system_Test( cur_lane, delay, assignTcmd, enable_movement)
86+
self.return_to_home()
8887

8988
return self.prep_homed and status
9089

@@ -157,7 +156,7 @@ def select_lane( self, lane ):
157156
"""
158157
self.failed_to_home = False
159158
if self.current_selected_lane != lane:
160-
self.logger.debug("HTLF: {} Homing to endstop".format(self.name))
159+
self.logger.debug("HTLF: {} Homing to endstop.".format(self.name))
161160
if self.return_to_home():
162161
self.selector_stepper_obj.move(self.calculate_lobe_movement( lane.index ), 50, 50, False)
163162
self.logger.debug("HTLF: {} selected".format(lane))

extras/AFC_assist.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ def assist(self, value):
640640

641641
def break_espooler(self):
642642
"""
643-
Helper function to "brake" n20 motors to hopefully help with keeping down backfeeding into MCU board
643+
Helper function to "brake" n20 motors to hopefully help with keeping down back-feeding into MCU board
644644
"""
645645
print_time = self.afc.toolhead.get_last_move_time()
646646
if self.afc_motor_enb is not None:

extras/AFC_buffer.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,11 @@ def __init__(self, config):
5757
self.multiplier_high = config.getfloat("multiplier_high", default=1.1, minval=1.0)
5858
self.multiplier_low = config.getfloat("multiplier_low", default=0.9, minval=0.0, maxval=1.0)
5959

60-
if self.enable_sensors_in_gui:
61-
self.adv_filament_switch_name = "filament_switch_sensor {}_{}".format(self.name, "expanded")
62-
self.fila_avd = add_filament_switch(self.adv_filament_switch_name, self.advance_pin, self.printer )
60+
self.adv_filament_switch_name = "{}_{}".format(self.name, "expanded")
61+
self.fila_avd = add_filament_switch(self.adv_filament_switch_name, self.advance_pin, self.printer, show_sensor=self.enable_sensors_in_gui )
6362

64-
self.trail_filament_switch_name = "filament_switch_sensor {}_{}".format(self.name, "compressed")
65-
self.fila_trail = add_filament_switch(self.trail_filament_switch_name, self.trailing_pin, self.printer )
63+
self.trail_filament_switch_name = "{}_{}".format(self.name, "compressed")
64+
self.fila_trail = add_filament_switch(self.trail_filament_switch_name, self.trailing_pin, self.printer, show_sensor=self.enable_sensors_in_gui )
6665

6766
self.printer.register_event_handler("klippy:ready", self._handle_ready)
6867

0 commit comments

Comments
 (0)