From 89c54714b615424e182d5a2e6751472217abcd4e Mon Sep 17 00:00:00 2001 From: Ryan Ghosh Date: Wed, 15 Oct 2025 18:40:21 -0700 Subject: [PATCH 01/13] Modify constructor for TradRackToolHead to match changes to ToolHead from Klipper3d/klipper@3ef760c through Klipper3d/klipper@ff8c8ea --- Kalico/klippy_module/trad_rack.py | 47 +++++++------------------------ 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index a5e6c02..801c4a9 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -2321,10 +2321,7 @@ def __init__(self, config, buffer_pull_speed, is_extruder_synced): except config.error: pass self.reactor = self.printer.get_reactor() - self.all_mcus = [ - m for n, m in self.printer.lookup_objects(module="mcu") - ] - self.mcu = self.all_mcus[0] + self.mcu = self.printer.lookup_object("mcu") if hasattr(toolhead, "LookAheadQueue"): self.lookahead = toolhead.LookAheadQueue() self.lookahead.set_flush_time(toolhead.BUFFER_TIME_HIGH) @@ -2347,23 +2344,12 @@ def __init__(self, config, buffer_pull_speed, is_extruder_synced): ) self.max_accel = max(self.sel_max_accel, self.fil_max_accel) self.min_cruise_ratio = config.getfloat( - "minimum_cruise_ratio", None, below=1.0, minval=0.0 + "minimum_cruise_ratio", 0.5, below=1.0, minval=0.0 ) - if self.min_cruise_ratio is None: - self.min_cruise_ratio = 0.5 - req_accel_to_decel = config.getfloat( - "max_accel_to_decel", None, above=0.0 - ) - if req_accel_to_decel is not None: - config.deprecate("max_accel_to_decel") - self.min_cruise_ratio = 1.0 - min( - 1.0, (req_accel_to_decel / self.max_accel) - ) - self.requested_accel_to_decel = self.min_cruise_ratio * self.max_accel self.square_corner_velocity = config.getfloat( "square_corner_velocity", 5.0, minval=0.0 ) - self.junction_deviation = self.max_accel_to_decel = 0.0 + self.junction_deviation = self.mcr_pseudo_accel = 0.0 self._calc_junction_deviation() # Input stall detection self.check_stall_time = 0.0 @@ -2377,26 +2363,13 @@ def __init__(self, config, buffer_pull_speed, is_extruder_synced): self.print_time = 0.0 self.special_queuing_state = "NeedPrime" self.priming_timer = None - # Flush tracking - self.flush_timer = self.reactor.register_timer(self._flush_handler) - self.do_kick_flush_timer = True - self.last_flush_time = self.last_sg_flush_time = ( - self.min_restart_time - ) = 0.0 - self.need_flush_time = self.step_gen_time = self.clear_history_time = ( - 0.0 - ) - # Kinematic step generation scan window time tracking - self.kin_flush_delay = toolhead.SDS_CHECK_TIME - self.kin_flush_times = [] - # Setup iterative solver - ffi_main, ffi_lib = chelper.get_ffi() - self.trapq = ffi_main.gc(ffi_lib.trapq_alloc(), ffi_lib.trapq_free) - self.trapq_append = ffi_lib.trapq_append - self.trapq_finalize_moves = ffi_lib.trapq_finalize_moves - # Motion flushing - self.step_generators = [] - self.flush_trapqs = [self.trapq] + # Setup for generating moves + self.motion_queuing = self.printer.load_object(config, "motion_queuing") + self.motion_queuing.register_flush_callback( + self._handle_step_flush, can_add_trapq=True + ) + self.trapq = self.motion_queuing.allocate_trapq() + self.trapq_append = self.motion_queuing.lookup_trapq_append() # Create kinematic class gcode = self.printer.lookup_object("gcode") self.Coord = gcode.Coord From e66d31bffba72f5fc960abbc1c989ad47ee5ce08 Mon Sep 17 00:00:00 2001 From: Ryan Ghosh Date: Wed, 15 Oct 2025 18:48:55 -0700 Subject: [PATCH 02/13] Remove hasattr check from d4e04db since the rest of the TradRackToolHead constructor is no longer compatible with older versions of Klipper anyway --- Kalico/klippy_module/trad_rack.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 801c4a9..48df037 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -2322,12 +2322,8 @@ def __init__(self, config, buffer_pull_speed, is_extruder_synced): pass self.reactor = self.printer.get_reactor() self.mcu = self.printer.lookup_object("mcu") - if hasattr(toolhead, "LookAheadQueue"): - self.lookahead = toolhead.LookAheadQueue() - self.lookahead.set_flush_time(toolhead.BUFFER_TIME_HIGH) - else: - self.move_queue = toolhead.MoveQueue(self) - self.move_queue.set_flush_time(toolhead.BUFFER_TIME_HIGH) + self.lookahead = toolhead.LookAheadQueue() + self.lookahead.set_flush_time(toolhead.BUFFER_TIME_HIGH) self.commanded_pos = [0.0, 0.0, 0.0, 0.0] # Velocity and acceleration control tr_config = config.getsection("trad_rack") From 85e66aceb0e660569fad9d0d38838573a4675dec Mon Sep 17 00:00:00 2001 From: Ryan Ghosh Date: Wed, 15 Oct 2025 21:27:14 -0700 Subject: [PATCH 03/13] Update step generator stuff to match Klipper3d/klipper@9399e73 --- Kalico/klippy_module/trad_rack.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 48df037..893e9f8 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -2410,7 +2410,6 @@ def __init__(self, toolhead, config, is_extruder_synced): rail.setup_itersolve("cartesian_stepper_alloc", axis.encode()) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - toolhead.register_step_generator(s.generate_steps) self.printer.register_event_handler( "stepper_enable:motor_off", self._motor_off ) @@ -2722,8 +2721,6 @@ def _sync(self, sync_type): self._prev_trapq = steppers[0].get_trapq() external_trapq = self.tr_toolhead.get_trapq() stepper_alloc = ffi_lib.cartesian_stepper_alloc(b"y") - prev_toolhead = self.toolhead - external_toolhead = self.tr_toolhead self.reset_fil_driver() new_pos = [0.0, 0.0, 0.0] elif sync_type == FIL_DRIVER_TO_EXTRUDER: @@ -2732,8 +2729,6 @@ def _sync(self, sync_type): extruder = self.toolhead.get_extruder() external_trapq = extruder.get_trapq() stepper_alloc = ffi_lib.extruder_stepper_alloc() - prev_toolhead = self.tr_toolhead - external_toolhead = self.toolhead new_pos = extruder.last_position if not isinstance(new_pos, list): new_pos = [new_pos, 0.0, 0.0] @@ -2750,8 +2745,6 @@ def _sync(self, sync_type): ) stepper.set_trapq(external_trapq) stepper.set_position(new_pos) - prev_toolhead.step_generators.remove(stepper.generate_steps) - external_toolhead.register_step_generator(stepper.generate_steps) self.sync_state = sync_type def sync_extruder_to_fil_driver(self): @@ -2770,20 +2763,14 @@ def unsync(self): if self.sync_state == EXTRUDER_TO_FIL_DRIVER: steppers = self._get_extruder_mcu_steppers() - prev_toolhead = self.toolhead - external_toolhead = self.tr_toolhead elif self.sync_state == FIL_DRIVER_TO_EXTRUDER: self.printer.send_event("trad_rack:unsyncing_from_extruder") steppers = self.fil_driver_rail.get_steppers() - prev_toolhead = self.tr_toolhead - external_toolhead = self.toolhead else: raise Exception("Invalid sync_state: %d" % self.sync_state) for i in range(len(steppers)): stepper = steppers[i] - external_toolhead.step_generators.remove(stepper.generate_steps) - prev_toolhead.register_step_generator(stepper.generate_steps) stepper.set_trapq(self._prev_trapq) stepper.set_stepper_kinematics(self._prev_sks[i]) stepper.set_rotation_distance(self._prev_rotation_dists[i]) From 5f80bdb0080b23ca1a4c13bc2a8d38e1b63b2baf Mon Sep 17 00:00:00 2001 From: Ryan Ghosh Date: Wed, 15 Oct 2025 22:15:40 -0700 Subject: [PATCH 04/13] Use separate minimum_cruise_ratio and square_corner_velocity settings for trad rack --- Kalico/klippy_module/trad_rack.py | 8 ++++---- docs/kalico/Config_Reference.md | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 893e9f8..c933238 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -2339,11 +2339,11 @@ def __init__(self, config, buffer_pull_speed, is_extruder_synced): "filament_max_accel", default=1500.0, above=0.0 ) self.max_accel = max(self.sel_max_accel, self.fil_max_accel) - self.min_cruise_ratio = config.getfloat( - "minimum_cruise_ratio", 0.5, below=1.0, minval=0.0 + self.min_cruise_ratio = tr_config.getfloat( + "minimum_cruise_ratio", 0.0, below=1.0, minval=0.0 ) - self.square_corner_velocity = config.getfloat( - "square_corner_velocity", 5.0, minval=0.0 + self.square_corner_velocity = tr_config.getfloat( + "square_corner_velocity", 0.0, minval=0.0 ) self.junction_deviation = self.mcr_pseudo_accel = 0.0 self._calc_junction_deviation() diff --git a/docs/kalico/Config_Reference.md b/docs/kalico/Config_Reference.md index 937ece8..442c590 100644 --- a/docs/kalico/Config_Reference.md +++ b/docs/kalico/Config_Reference.md @@ -219,6 +219,16 @@ toolhead_unload_length: #keep_servo_down_after_lane_load: False # If set to True, after loading filament into a lane the servo is # kept down to hold the filament in place. The default is False. +#minimum_cruise_ratio: 0.0 +# See the "printer" section of Kalico's Config Reference document +# for a description of this parameter. This parameter affects +# selector moves and filament moves made by Trad Rack. The default +# is 0.0. +#square_corner_velocity: 0.0 +# See the "printer" section of Kalico's Config Reference document +# for a description of this parameter. This parameter can affect +# selector moves and filament moves made by Trad Rack. The default +# is 0.0. #log_bowden_lengths: False # Whether to log bowden load length data and bowden unload length # data (to ~/bowden_load_lengths.csv and ~/bowden_unload_lengths.csv From a6e82a0d3905bc2bdf8427db2a2596d6c260a1a2 Mon Sep 17 00:00:00 2001 From: Ryan Ghosh Date: Fri, 17 Oct 2025 06:31:49 -0700 Subject: [PATCH 05/13] Remove _motor_off() function to match changes to kinematics from Klipper3d/klipper@c72d73e --- Kalico/klippy_module/trad_rack.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index c933238..0ff69f6 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -2410,10 +2410,6 @@ def __init__(self, toolhead, config, is_extruder_synced): rail.setup_itersolve("cartesian_stepper_alloc", axis.encode()) for s in self.get_steppers(): s.set_trapq(toolhead.get_trapq()) - self.printer.register_event_handler( - "stepper_enable:motor_off", self._motor_off - ) - # Setup boundary checks self.sel_max_velocity, self.sel_max_accel = ( toolhead.get_sel_max_velocity() @@ -2468,9 +2464,6 @@ def home(self, homing_state): for axis in homing_state.get_axes(): self._home_axis(homing_state, axis, self.rails[axis]) - def _motor_off(self, print_time): - self.limits = [(1.0, -1.0)] * self.stepper_count - def _check_endstops(self, move): end_pos = move.end_pos for i in range(self.stepper_count): From 69b2de2a7cec89728de63b7fdbd6d78818a8eb88 Mon Sep 17 00:00:00 2001 From: Ryan Ghosh Date: Fri, 17 Oct 2025 06:47:03 -0700 Subject: [PATCH 06/13] Minor changes to TradRackKinematics to match CartKinematics from Klipper3d/klipper@36be1cf, etc. --- Kalico/klippy_module/trad_rack.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 0ff69f6..1546f11 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -2429,8 +2429,7 @@ def __init__(self, toolhead, config, is_extruder_synced): self.is_extruder_synced = is_extruder_synced def get_steppers(self): - rails = self.rails - return [s for rail in rails for s in rail.get_steppers()] + return [s for rail in self.rails for s in rail.get_steppers()] def calc_position(self, stepper_positions): return [stepper_positions[rail.get_name()] for rail in self.rails] @@ -2441,11 +2440,7 @@ def set_position(self, newpos, homing_axes): if i in homing_axes: self.limits[i] = rail.get_range() - def note_z_not_homed(self): - # Helper for Safe Z Home - pass - - def _home_axis(self, homing_state, axis, rail): + def home_axis(self, homing_state, axis, rail): # Determine movement position_min, position_max = rail.get_range() hi = rail.get_homing_info() @@ -2462,7 +2457,7 @@ def _home_axis(self, homing_state, axis, rail): def home(self, homing_state): # Each axis is homed independently and in order for axis in homing_state.get_axes(): - self._home_axis(homing_state, axis, self.rails[axis]) + self.home_axis(homing_state, axis, self.rails[axis]) def _check_endstops(self, move): end_pos = move.end_pos From a5166a3df27ed95561708cced8511cd888a596f7 Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Sat, 25 Oct 2025 09:42:40 -0500 Subject: [PATCH 07/13] query for entry sensor status --- Kalico/klippy_module/trad_rack.py | 18 ++++++++++++++++++ docs/kalico/Status_Reference.md | 2 ++ 2 files changed, 20 insertions(+) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 41f9c89..41f447f 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -425,6 +425,11 @@ def __init__(self, config): self.cmd_TR_PRINT_TOOL_GROUPS, desc=self.cmd_TR_PRINT_TOOL_GROUPS_help, ) + self.gcode.register_command( + "TR_QUERY_LANE_ENTRY_SENSORS", + self.cmd_TR_QUERY_LANE_ENTRY_SENSORS, + desc=self.cmd_TR_QUERY_LANE_ENTRY_SENSORS_help, + ) if register_toolchange_commands: for i in range(self.lane_count): self.gcode.register_command( @@ -1134,6 +1139,18 @@ def cmd_TR_PRINT_TOOL_GROUPS(self, gcmd): msg += "\n" gcmd.respond_info(msg) + cmd_TR_QUERY_LANE_ENTRY_SENSORS_help = "Query the status of the lane entry sensors" + + def cmd_TR_QUERY_LANE_ENTRY_SENSORS(self, gcmd): + triggered_sensors = self._get_lane_entry_sensors_active() + msg = "" + for lane, triggered in enumerate(triggered_sensors): + if not triggered[0] and not triggered[1]: + msg += "Lane {}: UNAVAILABLE".format(lane) + else: + msg += "Lane {}: {}".format(lane, "UNTRIGGERED" if triggered[0] else "Triggered") + gcmd.respond_info(msg) + # helper functions def _lower_servo(self, toolhead_dwell=False): self.tr_toolhead.wait_moves() @@ -2430,6 +2447,7 @@ def get_status(self, eventtime): "next_tool": self.next_tool, "tool_map": self.tool_map, "selector_homed": self._is_selector_homed(), + "lane_entry_sensors": self._get_lane_entry_sensors_active(), } diff --git a/docs/kalico/Status_Reference.md b/docs/kalico/Status_Reference.md index 19f226a..0459440 100644 --- a/docs/kalico/Status_Reference.md +++ b/docs/kalico/Status_Reference.md @@ -7,6 +7,7 @@ but only contains items pertaining to Trad Rack. ## trad_rack The following information is available in the `trad_rack` object: + - `curr_lane`: The lane the selector is currently positioned at. - `active_lane`: The lane currently loaded in the toolhead. - `next_lane`: The next lane to load to the toolhead if a toolchange @@ -17,6 +18,7 @@ The following information is available in the `trad_rack` object: lane. The tool number for a specified lane can be accessed with `tool_map[]`. - `selector_homed`: Whether or not the selector axis is homed. +- `lane_entry_sensors[]`: An array of lists, each list indicating whether a lane entry sensor is active and triggered for each lane ## save_variables From c68c18086ba79d866dcf5bfabbd96e3500ba150e Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Sat, 25 Oct 2025 09:54:20 -0500 Subject: [PATCH 08/13] swap triggered state pos in query swapped the positiion of the lane entry sensor status in the TR_QUERY_LANE_ENTRY_SENSORS --- Kalico/klippy_module/trad_rack.py | 2 +- docs/kalico/Status_Reference.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 41f447f..e941151 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -1148,7 +1148,7 @@ def cmd_TR_QUERY_LANE_ENTRY_SENSORS(self, gcmd): if not triggered[0] and not triggered[1]: msg += "Lane {}: UNAVAILABLE".format(lane) else: - msg += "Lane {}: {}".format(lane, "UNTRIGGERED" if triggered[0] else "Triggered") + msg += "Lane {}: {}".format(lane, "TRIGGERED" if triggered[0] else "UNTRIGGERED") gcmd.respond_info(msg) # helper functions diff --git a/docs/kalico/Status_Reference.md b/docs/kalico/Status_Reference.md index 0459440..57f0c44 100644 --- a/docs/kalico/Status_Reference.md +++ b/docs/kalico/Status_Reference.md @@ -18,7 +18,7 @@ The following information is available in the `trad_rack` object: lane. The tool number for a specified lane can be accessed with `tool_map[]`. - `selector_homed`: Whether or not the selector axis is homed. -- `lane_entry_sensors[]`: An array of lists, each list indicating whether a lane entry sensor is active and triggered for each lane +- `lane_entry_sensors[]`: An array of tuples, each tuple indicates `(Triggered state, Untriggered State)` ## save_variables From 7dcb7f55ca0b5decb39f59e5a9f85fc8131a2410 Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Sat, 25 Oct 2025 10:07:21 -0500 Subject: [PATCH 09/13] gcode docs for lane entry sensors --- docs/kalico/G-Codes.md | 85 +++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/docs/kalico/G-Codes.md b/docs/kalico/G-Codes.md index b699d19..7becebb 100644 --- a/docs/kalico/G-Codes.md +++ b/docs/kalico/G-Codes.md @@ -5,45 +5,51 @@ This document is modeled after Kalico's contains items pertaining to Trad Rack. **Table of Contents** + - [General commands](#general-commands) - - [TR\_HOME](#tr_home) - - [TR\_GO\_TO\_LANE](#tr_go_to_lane) - - [TR\_LOAD\_LANE](#tr_load_lane) - - [TR\_LOAD\_TOOLHEAD](#tr_load_toolhead) + - [TR_HOME](#tr_home) + - [TR_GO_TO_LANE](#tr_go_to_lane) + - [TR_LOAD_LANE](#tr_load_lane) + - [TR_LOAD_TOOLHEAD](#tr_load_toolhead) - [T0, T1, T2, etc.](#t0-t1-t2-etc) - - [TR\_UNLOAD\_TOOLHEAD](#tr_unload_toolhead) - - [TR\_SERVO\_DOWN](#tr_servo_down) - - [TR\_SERVO\_UP](#tr_servo_up) - - [TR\_SET\_ACTIVE\_LANE](#tr_set_active_lane) - - [TR\_RESET\_ACTIVE\_LANE](#tr_reset_active_lane) - - [TR\_RESUME](#tr_resume) - - [TR\_LOCATE\_SELECTOR](#tr_locate_selector) - - [TR\_NEXT](#tr_next) - - [TR\_SYNC\_TO\_EXTRUDER](#tr_sync_to_extruder) - - [TR\_UNSYNC\_FROM\_EXTRUDER](#tr_unsync_from_extruder) + - [TR_UNLOAD_TOOLHEAD](#tr_unload_toolhead) + - [TR_SERVO_DOWN](#tr_servo_down) + - [TR_SERVO_UP](#tr_servo_up) + - [TR_SET_ACTIVE_LANE](#tr_set_active_lane) + - [TR_RESET_ACTIVE_LANE](#tr_reset_active_lane) + - [TR_RESUME](#tr_resume) + - [TR_LOCATE_SELECTOR](#tr_locate_selector) + - [TR_NEXT](#tr_next) + - [TR_SYNC_TO_EXTRUDER](#tr_sync_to_extruder) + - [TR_UNSYNC_FROM_EXTRUDER](#tr_unsync_from_extruder) - [Calibration and testing](#calibration-and-testing) - - [TR\_SERVO\_TEST](#tr_servo_test) - - [TR\_CALIBRATE\_SELECTOR](#tr_calibrate_selector) - - [TR\_SET\_HOTEND\_LOAD\_LENGTH](#tr_set_hotend_load_length) - - [TR\_DISCARD\_BOWDEN\_LENGTHS](#tr_discard_bowden_lengths) + - [TR_SERVO_TEST](#tr_servo_test) + - [TR_CALIBRATE_SELECTOR](#tr_calibrate_selector) + - [TR_SET_HOTEND_LOAD_LENGTH](#tr_set_hotend_load_length) + - [TR_DISCARD_BOWDEN_LENGTHS](#tr_discard_bowden_lengths) - [Tool mapping](#tool-mapping) - - [TR\_ASSIGN\_LANE](#tr_assign_lane) - - [TR\_SET\_DEFAULT\_LANE](#tr_set_default_lane) - - [TR\_RESET\_TOOL\_MAP](#tr_reset_tool_map) - - [TR\_PRINT\_TOOL\_MAP](#tr_print_tool_map) - - [TR\_PRINT\_TOOL\_GROUPS](#tr_print_tool_groups) + - [TR_ASSIGN_LANE](#tr_assign_lane) + - [TR_SET_DEFAULT_LANE](#tr_set_default_lane) + - [TR_RESET_TOOL_MAP](#tr_reset_tool_map) + - [TR_PRINT_TOOL_MAP](#tr_print_tool_map) + - [TR_PRINT_TOOL_GROUPS](#tr_print_tool_groups) +- [Lane Entry Sensors](#lane-entry-sensors) + - [TR\_QUERY\_LANE\_ENTRY\_SENSORS] - [Macros](#macros) ## General commands ### TR_HOME + `TR_HOME`: Homes the selector. ### TR_GO_TO_LANE + `TR_GO_TO_LANE LANE=`: Moves the selector to the specified lane. ### TR_LOAD_LANE + `TR_LOAD_LANE LANE= [RESET_SPEED=<0|1>]`: Ensures filament is loaded into the module for the specified lane by prompting the user to insert filament, loading filament from the module into the @@ -56,11 +62,12 @@ the bowden speed settings are used). If not specified, RESET_SPEED defaults to 1. ### TR_LOAD_TOOLHEAD + `TR_LOAD_TOOLHEAD LANE=|TOOL= [MIN_TEMP=] [EXACT_TEMP=] [BOWDEN_LENGTH=] [EXTRUDER_LOAD_LENGTH=] [HOTEND_LOAD_LENGTH=]`: Loads filament from the specified lane or -tool into the toolhead*. Either LANE or TOOL must be specified. If +tool into the toolhead\*. Either LANE or TOOL must be specified. If both are specified, then LANE takes precedence. If there is already an "active lane" because the toolhead has been loaded beforehand, it will be unloaded before loading the new filament. If `MIN_TEMP` is @@ -80,12 +87,14 @@ details on the difference between lanes and tools and how they relate to each other. ### T0, T1, T2, etc. -`T`: Equivalent to calling + +`T`: Equivalent to calling `TR_LOAD_TOOLHEAD TOOL=`. All of the optional parameters accepted by the TR_LOAD_TOOLHEAD command can also be used with these commands. ### TR_UNLOAD_TOOLHEAD + `TR_UNLOAD_TOOLHEAD [MIN_TEMP=] [EXACT_TEMP=] [RESET_SPEED=<0|1>]`: Unloads filament from the toolhead and back into its module. If `MIN_TEMP` is specified and @@ -104,6 +113,7 @@ the bowden speed settings are used). If not specified, `RESET_SPEED` defaults to 1. ### TR_SERVO_DOWN + `TR_SERVO_DOWN [FORCE=<0|1>]`: Moves the servo to bring the drive gear down. The selector must be moved to a valid lane before using this command, unless FORCE is 1. If not specified, FORCE defaults to 0. The @@ -111,19 +121,23 @@ FORCE parameter is unsafe for normal use and should only be used when the servo is not attached to Trad Rack's carriage. ### TR_SERVO_UP + `TR_SERVO_UP`: Moves the servo to bring the drive gear up. ### TR_SET_ACTIVE_LANE + `TR_SET_ACTIVE_LANE LANE=`: Tells Trad Rack to assume the toolhead has been loaded with filament from the specified lane. The selector's position will also be inferred from this lane, and the selector motor will be enabled if it isn't already. ### TR_RESET_ACTIVE_LANE + `TR_RESET_ACTIVE_LANE`: Tells Trad Rack to assume the toolhead has not been loaded. ### TR_RESUME + `TR_RESUME`: Completes necessary actions for Trad Rack to recover (and/or checks that Trad Rack is ready to continue), then resumes the print if all of those actions complete successfully. For example, if @@ -134,6 +148,7 @@ Trad Rack has paused the print and requires user interaction or confirmation before attempting to recover and resume. ### TR_LOCATE_SELECTOR + `TR_LOCATE_SELECTOR`: Ensures the position of Trad Rack's selector is known so that it is ready for a print. If the user needs to take an action, they will be prompted to do so and the print will be paused @@ -148,10 +163,12 @@ filament sensor is triggered but no active lane is currently set. It is recommended to call this command in the print start gcode. ### TR_NEXT + `TR_NEXT`: You will be prompted to use this command if Trad Rack requires user confirmation before continuing an action. ### TR_SYNC_TO_EXTRUDER + `TR_SYNC_TO_EXTRUDER`: Syncs Trad Rack's filament driver to the extruder during printing, as well as during any extrusion moves within toolhead loading or unloading that would normally involve only the @@ -163,6 +180,7 @@ sync_to_extruder to True in the [trad_rack config section](Config_Reference.md#trad_rack). ### TR_UNSYNC_FROM_EXTRUDER + `TR_UNSYNC_FROM_EXTRUDER`: Unsyncs Trad Rack's filament driver from the extruder during printing, as well as during any extrusion moves within toolhead loading or unloading that normally involve only the @@ -178,6 +196,7 @@ Calibration procedures that should be run before using Trad Rack are covered by the [Quick Start document](/docs/Quick_Start.md): ### TR_SERVO_TEST + `TR_SERVO_TEST [ANGLE=]`: Moves the servo to the specified ANGLE relative to the down position. If ANGLE is not specified, the servo will be moved to the up position defined by servo_up_angle from @@ -186,12 +205,14 @@ This command is meant for testing different servo angles in order to find the correct value for servo_up_angle. ### TR_CALIBRATE_SELECTOR + `TR_CALIBRATE_SELECTOR`: Initiates the process of calibrating lane_spacing, as well as the min, endstop, and max positions of the selector motor. You will be guided through the selector calibration process via messages in the console. ### TR_SET_HOTEND_LOAD_LENGTH + `TR_SET_HOTEND_LOAD_LENGTH VALUE=|ADJUST=`: Sets the value of hotend_load_length, overriding its value from the [trad_rack config section](Config_Reference.md#trad_rack). Does not @@ -201,6 +222,7 @@ parameter is used, the adjustment will be added to the current value of hotend_load_length. ### TR_DISCARD_BOWDEN_LENGTHS + `TR_DISCARD_BOWDEN_LENGTHS [MODE=[ALL|LOAD|UNLOAD]]`: Discards saved values for "bowden_load_length" and/or "bowden_unload_length" (see [bowden lengths](/docs/Tuning.md#bowden-lengths) for details on how @@ -222,6 +244,7 @@ tool mapping/lane groups. See the [Tool Mapping document](/docs/Tool_Mapping.md) for more details: ### TR_ASSIGN_LANE + `TR_ASSIGN_LANE LANE= TOOL= [SET_DEFAULT=<0|1>]`: Assigns the specified LANE to the specified TOOL. If SET_DEFAULT is 1, @@ -229,26 +252,38 @@ LANE will become the default lane for the tool. If not specified, SET_DEFAULT defaults to 0. ### TR_SET_DEFAULT_LANE + `TR_SET_DEFAULT_LANE LANE= [TOOL=]`: If TOOL is specified, LANE will be set as the default lane for the tool. If TOOL is not specified, LANE will be set as the default lane for its currently-assigned tool. ### TR_RESET_TOOL_MAP + `TR_RESET_TOOL_MAP`: Resets lane/tool mapping. Each tool will be mapped to a lane group consisting of a single lane with the same index as the tool. ### TR_PRINT_TOOL_MAP + `TR_PRINT_TOOL_MAP`: Prints a table of the lane/tool mapping to the console, with rows corresponding to tools and columns corresponding to lanes. ### TR_PRINT_TOOL_GROUPS + `TR_PRINT_TOOL_GROUPS`: Prints a list of lanes assigned to each tool to the console. If a tool has multiple lanes assigned to it, the default lane will be indicated. +## Lane Entry Sensors + +The following commands are available for viewing lane entry sensor trigger state + +### TR_QUERY_LANE_ENTRY_SENSORS + +`TR_QUERY_LANE_ENTRY_SENSOR`: Prints a list of tuples corresponding to the (Triggered, Untriggered) state of the sensor in each lane. Prints `UNAVAILABE` if lane sensor is not configured for a lane. + ## Macros In addition to the above gcode commands, the From 73b9112e57418a6de14ebcd2f2053a6dfc3d1c4e Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Sat, 25 Oct 2025 20:08:00 -0500 Subject: [PATCH 10/13] fix evaluation for None type --- Kalico/klippy_module/trad_rack.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index 17c2158..b2befd5 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -1145,10 +1145,11 @@ def cmd_TR_QUERY_LANE_ENTRY_SENSORS(self, gcmd): triggered_sensors = self._get_lane_entry_sensors_active() msg = "" for lane, triggered in enumerate(triggered_sensors): - if not triggered[0] and not triggered[1]: + if triggered is None: msg += "Lane {}: UNAVAILABLE".format(lane) else: msg += "Lane {}: {}".format(lane, "TRIGGERED" if triggered[0] else "UNTRIGGERED") + msg += "\n" gcmd.respond_info(msg) # helper functions From a79783e9131aac378f21d06fff8d7f7d6e171373 Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Sat, 25 Oct 2025 20:18:49 -0500 Subject: [PATCH 11/13] make docs match outputs --- docs/kalico/G-Codes.md | 4 +++- docs/kalico/Status_Reference.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/kalico/G-Codes.md b/docs/kalico/G-Codes.md index 7becebb..d69c2de 100644 --- a/docs/kalico/G-Codes.md +++ b/docs/kalico/G-Codes.md @@ -282,7 +282,9 @@ The following commands are available for viewing lane entry sensor trigger state ### TR_QUERY_LANE_ENTRY_SENSORS -`TR_QUERY_LANE_ENTRY_SENSOR`: Prints a list of tuples corresponding to the (Triggered, Untriggered) state of the sensor in each lane. Prints `UNAVAILABE` if lane sensor is not configured for a lane. +`TR_QUERY_LANE_ENTRY_SENSOR`: Prints a list of the trigger state of +the lane entry sensor on each lane. Will be one of +`UNAVAILABLE | TRIGGERED| UNTRIGGERED` ## Macros diff --git a/docs/kalico/Status_Reference.md b/docs/kalico/Status_Reference.md index 57f0c44..f53b137 100644 --- a/docs/kalico/Status_Reference.md +++ b/docs/kalico/Status_Reference.md @@ -18,7 +18,9 @@ The following information is available in the `trad_rack` object: lane. The tool number for a specified lane can be accessed with `tool_map[]`. - `selector_homed`: Whether or not the selector axis is homed. -- `lane_entry_sensors[]`: An array of tuples, each tuple indicates `(Triggered state, Untriggered State)` +- `lane_entry_sensors[]`: An array indicating the status of each lane. Each lane will either be + - `None` if no sensor assigned + - A Tuple of boolean values, for `(Triggered State, Untriggered State)` ## save_variables From cb2df9df415c7d333a58e130393e9aae769cd8be Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Sun, 26 Oct 2025 08:00:29 -0500 Subject: [PATCH 12/13] Codify conventions - Added extension recommendations for vscode - added .editorconfig to codify formatting support for most other editors I set the settings for the TOC to use `2..6`, which will cause all TOC create/updates to ignore the top level heading, and then will create an entry for H2 - H6. (cherry picked from commit 15101e8bee622fc5f9d608ee81bbea4257412b76) --- .editorconfig | 12 ++++++++++++ .vscode/extensions.json | 7 +++++++ .vscode/settings.json | 6 ++++-- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .editorconfig create mode 100644 .vscode/extensions.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f553378 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{py,sh}] +indent_style = space +indent_size = 4 diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c1d1f2a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "yzhang.markdown-all-in-one", + "EditorConfig.EditorConfig", + "dannymcgee.klipper" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 7685ac0..7e6ac04 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ { "editor.rulers": [ 70, 80, 120 - ] -} \ No newline at end of file + ], + "markdown.extension.toc.levels": "2..6", + "markdown.extension.toc.updateOnSave": true +} From a1c5a3fd192ef1c1dd39a8a927fec44b04daf8c8 Mon Sep 17 00:00:00 2001 From: Brian Vanderbusch Date: Tue, 28 Oct 2025 14:25:39 -0500 Subject: [PATCH 13/13] pin state tracking for fil sensors --- Kalico/klippy_module/trad_rack.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Kalico/klippy_module/trad_rack.py b/Kalico/klippy_module/trad_rack.py index b2befd5..9fdf237 100755 --- a/Kalico/klippy_module/trad_rack.py +++ b/Kalico/klippy_module/trad_rack.py @@ -1147,7 +1147,7 @@ def cmd_TR_QUERY_LANE_ENTRY_SENSORS(self, gcmd): for lane, triggered in enumerate(triggered_sensors): if triggered is None: msg += "Lane {}: UNAVAILABLE".format(lane) - else: + else: msg += "Lane {}: {}".format(lane, "TRIGGERED" if triggered[0] else "UNTRIGGERED") msg += "\n" gcmd.respond_info(msg) @@ -2353,6 +2353,19 @@ def _set_lane_entry_sensors_active(self, sensors_active): trigger_active, untrigger_active = sensors_active[lane] sensor.set_trigger_active(trigger_active) sensor.set_untrigger_active(untrigger_active) + def _get_lane_entry_sensors_state(self, gcmd): + sensors_state = [None] * self.lane_count + # return the last raw state reported by each sensor (or None) + msg = "trad_rack: Lane entry sensors state:\n" + for lane in range(self.lane_count): + sensor = self.lane_entry_sensors[lane] + if sensor is not None: + msg += "Lane {}: {}\n".format(lane, "OPEN" if 0 in sensor.state else "CLOSED") + sensors_state[lane] = sensor.state + else: + sensors_state[lane] = "UNAVAILABLE" + msg += "\n" + gcmd.respond_info(msg) # resume callbacks def _resume_load_toolhead(self): @@ -2448,7 +2461,7 @@ def get_status(self, eventtime): "next_tool": self.next_tool, "tool_map": self.tool_map, "selector_homed": self._is_selector_homed(), - "lane_entry_sensors": self._get_lane_entry_sensors_active(), + "lane_entry_sensors": self._get_lane_entry_sensors_state(), } @@ -2987,7 +3000,6 @@ def __init__( untrigger_only_when_printing, trigger_only_when_printing, ] - if allow_duplicate_pins: # disable config checks for duplicate pins pin_desc = pin @@ -3003,7 +3015,11 @@ def __init__( buttons.register_buttons([pin], self.sensor_callback) self.printer.register_event_handler("klippy:ready", self.handle_ready) + # last raw state reported by the button callback (None if unknown) + # state values come from the buttons framework (usually 0/1) + self.state = None + # active flags control whether trigger/untrigger callbacks will run self.active = [False, False] def handle_ready(self): @@ -3012,6 +3028,9 @@ def handle_ready(self): self.active[state] = True def sensor_callback(self, eventtime, state): + # always record the last raw sensor state so callers can query it + # even when callbacks/auto-reset logic prevents triggering handlers + self.state = state idle_timeout = self.printer.lookup_object("idle_timeout") printing = idle_timeout.get_status(eventtime)["state"] == "Printing" if (