Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Touch][Threshold] Corrects Attempt After Max Retry & STD to MAX #202

Merged
merged 6 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 62 additions & 58 deletions scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
)

atypes = {"median": "median", "average": "average"}
self.samples_config = {

Check warning on line 173 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "samples_config" is partially unknown   Type of "samples_config" is "dict[str, Unknown]" (reportUnknownMemberType)

Check warning on line 173 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "samples_config" is partially unknown   Type of "samples_config" is "dict[str, Unknown]" (reportUnknownMemberType)
"samples": config.getfloat("samples", 5, above=0.0),
"retract_dist": config.getfloat("samples_retract_dist", 5, above=0.0),
"tolerance": config.getfloat("samples_tolerance", 0.2, minval=0.0),
Expand Down Expand Up @@ -215,7 +215,7 @@
"scanner_touch_max_speed", 10, above=0, maxval=30
)
## NEW VARIABLES HERE
self.scanner_touch_config = {

Check warning on line 218 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "scanner_touch_config" is partially unknown   Type of "scanner_touch_config" is "dict[str, Unknown]" (reportUnknownMemberType)

Check warning on line 218 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "scanner_touch_config" is partially unknown   Type of "scanner_touch_config" is "dict[str, Unknown]" (reportUnknownMemberType)
"accel": config.getfloat("scanner_touch_accel", 100, above=0, minval=100),
"max_speed": max_speed_value,
"speed": config.getfloat("scanner_touch_speed", 3, maxval=max_speed_value),
Expand All @@ -241,7 +241,7 @@
raise self.printer.command_error(
"Please change detect_threshold_z to scanner_touch_threshold in printer.cfg"
)
self.detect_threshold_z = self.scanner_touch_config["threshold"]

Check warning on line 244 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "detect_threshold_z" is unknown (reportUnknownMemberType)

Check warning on line 244 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "scanner_touch_config" is partially unknown   Type of "scanner_touch_config" is "dict[str, Unknown]" (reportUnknownMemberType)

Check warning on line 244 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "detect_threshold_z" is unknown (reportUnknownMemberType)

Check warning on line 244 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "scanner_touch_config" is partially unknown   Type of "scanner_touch_config" is "dict[str, Unknown]" (reportUnknownMemberType)
self.previous_probe_success = None

self.cal_config = {
Expand Down Expand Up @@ -278,7 +278,7 @@
self._stream_buffer = []
self._stream_buffer_limit = STREAM_BUFFER_LIMIT_DEFAULT
self._stream_buffer_limit_new = self._stream_buffer_limit
self._stream_samples_queue = queue.Queue()

Check warning on line 281 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "_stream_samples_queue" is partially unknown   Type of "_stream_samples_queue" is "Queue[Unknown]" (reportUnknownMemberType)

Check warning on line 281 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "_stream_samples_queue" is partially unknown   Type of "_stream_samples_queue" is "Queue[Unknown]" (reportUnknownMemberType)
self._stream_flush_event = threading.Event()
self._log_stream = None
self._data_filter = AlphaBetaFilter(
Expand Down Expand Up @@ -314,7 +314,7 @@
)
self._mcu.register_config_callback(self._build_config)
self._mcu.register_response(
self._handle_scanner_data, self.sensor.lower() + "_data"

Check warning on line 317 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "_handle_scanner_data" is partially unknown   Type of "_handle_scanner_data" is "(params: Unknown) -> None" (reportUnknownMemberType)

Check warning on line 317 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Argument type is partially unknown   Argument corresponds to parameter "callback" in function "register_response"   Argument type is "(params: Unknown) -> None" (reportUnknownArgumentType)

Check warning on line 317 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "_handle_scanner_data" is partially unknown   Type of "_handle_scanner_data" is "(params: Unknown) -> None" (reportUnknownMemberType)

Check warning on line 317 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Argument type is partially unknown   Argument corresponds to parameter "callback" in function "register_response"   Argument type is "(params: Unknown) -> None" (reportUnknownArgumentType)
)
# Register webhooks
webhooks = self.printer.lookup_object("webhooks")
Expand Down Expand Up @@ -400,11 +400,11 @@
self.calibration_method = "scan"
self._start_calibration(gcmd)

def _get_common_variables(self, gcmd: GCodeCommand):

Check warning on line 403 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Return type, "dict[str, Unknown]", is partially unknown (reportUnknownParameterType)

Check warning on line 403 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Return type, "dict[str, Unknown]", is partially unknown (reportUnknownParameterType)
return {

Check warning on line 404 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Return type, "dict[str, Unknown]", is partially unknown (reportUnknownVariableType)

Check warning on line 404 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Return type, "dict[str, Unknown]", is partially unknown (reportUnknownVariableType)
"speed": gcmd.get_float(
"SPEED",
self.scanner_touch_config["speed"],

Check warning on line 407 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Type of "scanner_touch_config" is partially unknown   Type of "scanner_touch_config" is "dict[str, Unknown]" (reportUnknownMemberType)

Check warning on line 407 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Type of "scanner_touch_config" is partially unknown   Type of "scanner_touch_config" is "dict[str, Unknown]" (reportUnknownMemberType)
above=0,
maxval=self.scanner_touch_config["max_speed"],
),
Expand Down Expand Up @@ -461,7 +461,6 @@
manual_z_offset = gcmd.get_float(
"Z_OFFSET", self.scanner_touch_config["z_offset"], minval=0
)

# Debugging information
self.log_debug_info(
vars["verbose"],
Expand Down Expand Up @@ -561,7 +560,7 @@

result = self.start_touch(gcmd, touch_settings, vars["verbose"])

standard_deviation = result["standard_deviation"]
max_deviation = result["max_deviation"]
final_position = result["final_position"]
retries = result["retries"]
success = result["success"]
Expand All @@ -577,7 +576,7 @@
self.log_debug_info(
vars["verbose"],
gcmd,
f"Standard Deviation: {standard_deviation:.4f}",
f"Maximum Deviation: {max_deviation:.4f}",
)
if calibrate == 1:
self._calibrate(
Expand Down Expand Up @@ -610,6 +609,7 @@
randomize = touch_settings.randomize

original_threshold = self.detect_threshold_z
deviation = None
try:
self.detect_threshold_z = test_threshold
# Set the initial position for the toolhead
Expand All @@ -623,6 +623,13 @@
original_position = initial_position[:]

while len(samples) < num_samples:
if retries >= max_retries:
self.detect_threshold_z = original_threshold
self.trigger_method = TriggerMethod.SCAN
self._zhop()
raise gcmd.error(
f"Exceeded maximum attempts [{retries}/{int(max_retries)}]"
)
if randomize > 0 and new_retry:
# Generate random offsets
x_offset = random.uniform(-randomize, randomize)
Expand All @@ -649,6 +656,7 @@
)
except self.printer.command_error as e:
if self.printer.is_shutdown():
self.detect_threshold_z = original_threshold
self.trigger_method = TriggerMethod.SCAN
raise self.printer.command_error(
"Touch procedure interrupted due to printer shutdown"
Expand All @@ -674,12 +682,6 @@

deviation = round(deviation, 4)
if deviation > tolerance:
if retries >= max_retries:
self.trigger_method = TriggerMethod.SCAN
self._zhop()
raise gcmd.error(
f"Exceeded maximum attempts [{retries}/{int(max_retries)}]"
)
self.log_debug_info(
verbose,
gcmd,
Expand All @@ -698,42 +700,45 @@
f"Deviation: {deviation:.4f}\nNew Average: {average:.4f}\nTolerance: {tolerance:.4f}",
)

std_dev = np.std(samples)
gcmd.respond_info(
f"Completed {len(samples)} touches with a standard deviation of {std_dev:.4f}"
)
position_difference = initial_position[2] - self.toolhead.get_position()[2]
adjusted_difference = initial_position[2] - np.mean(samples)
self.log_debug_info(
verbose,
gcmd,
f"Position Difference: {position_difference:.4f}\nAdjusted Difference: {adjusted_difference:.4f}",
)
if len(samples) == num_samples and deviation <= tolerance:
gcmd.respond_info(
f"Completed {len(samples)} touches with a max deviation of {deviation:.4f}"
)
position_difference = (
initial_position[2] - self.toolhead.get_position()[2]
)
adjusted_difference = initial_position[2] - np.mean(samples)
self.log_debug_info(
verbose,
gcmd,
f"Position Difference: {position_difference:.4f}\nAdjusted Difference: {adjusted_difference:.4f}",
)

initial_position[2] = float(adjusted_difference - position_difference)
formatted_position = [f"{coord:.2f}" for coord in initial_position]
self.log_debug_info(
verbose, gcmd, f"Updated Initial Position: {formatted_position}"
)
if manual_z_offset > 0:
gcmd.respond_info(f"Offsetting by {manual_z_offset:.3f}")
initial_position[2] = initial_position[2] - manual_z_offset
self.toolhead.set_position(initial_position)
self.toolhead.wait_moves()
self.toolhead.flush_step_generation()
self.trigger_method = TriggerMethod.SCAN
self.previous_probe_success = 1
initial_position[2] = float(adjusted_difference - position_difference)
formatted_position = [f"{coord:.2f}" for coord in initial_position]
self.log_debug_info(
verbose, gcmd, f"Updated Initial Position: {formatted_position}"
)
if manual_z_offset > 0:
gcmd.respond_info(f"Offsetting by {manual_z_offset:.3f}")
initial_position[2] = initial_position[2] - manual_z_offset
self.toolhead.set_position(initial_position)
self.toolhead.wait_moves()
self.toolhead.flush_step_generation()
self.trigger_method = TriggerMethod.SCAN
self.previous_probe_success = 1

# Return relevant data
self.detect_threshold_z = original_threshold
# Return relevant data
self.detect_threshold_z = original_threshold
return {
"samples": samples,
"standard_deviation": std_dev,
"max_deviation": deviation,
"final_position": initial_position,
"retries": retries,
"success": self.previous_probe_success,
}
except self.printer.command_error:
self.detect_threshold_z = original_threshold
self.trigger_method = TriggerMethod.SCAN
if hasattr(kinematics, "note_z_not_homed"):
kinematics.note_z_not_homed()
Expand Down Expand Up @@ -791,7 +796,7 @@
max_acceptable_retries = round(
confirmation_retries * THRESHOLD_ACCEPTANCE_FACTOR
)
max_acceptable_std_dev = vars["target"]
max_acceptable_max_dev = vars["target"]

verbose = vars["verbose"]

Expand Down Expand Up @@ -876,8 +881,8 @@
if result["success"]:
# Check if this result meets "good" criteria
if result["retries"] <= max_acceptable_retries and (
result["standard_deviation"] is not None
and result["standard_deviation"] <= max_acceptable_std_dev
result["max_deviation"] is not None
and result["max_deviation"] <= max_acceptable_max_dev
):
# Increase threshold_max by 3 steps above the current threshold, only if it hasn't been increased before
if not has_increased_threshold_max:
Expand All @@ -898,24 +903,23 @@
gcmd, touch_settings, verbose
)
if not repeat_result["success"] or (
repeat_result["standard_deviation"]
> max_acceptable_std_dev
repeat_result["max_deviation"] > max_acceptable_max_dev
):
gcmd.respond_info(
f"Qualify attempt {attempt + 1} failed for threshold {current_threshold}"
)
consistent_results = False
break
gcmd.respond_info(
f"Qualify attempt {attempt + 1} successful with std dev: {repeat_result['standard_deviation']:.5f}"
f"Qualify attempt {attempt + 1} successful with max dev: {repeat_result['max_deviation']:.5f}"
)

# Save only successful repeat attempts in results
result["consistent_results"] = (
consistent_results # Mark if it passed repeatability checks
)
result["standard_deviation"] = (
repeat_result["standard_deviation"]
result["max_deviation"] = (
repeat_result["max_deviation"]
if consistent_results
else None
)
Expand Down Expand Up @@ -946,13 +950,13 @@
return # Exit as there's no best threshold to save

if consistent_results:
# Find the best consistent result based on minimum retries and standard deviation
# Find the best consistent result based on minimum retries and max deviation
best_result = min(
consistent_results,
key=lambda x: (
x["retries"],
x["standard_deviation"]
if x["standard_deviation"] is not None
x["max_deviation"]
if x["max_deviation"] is not None
else float("inf"),
),
)
Expand All @@ -964,8 +968,8 @@
results,
key=lambda x: (
x["retries"],
x["standard_deviation"]
if x["standard_deviation"] is not None
x["max_deviation"]
if x["max_deviation"] is not None
else float("inf"),
),
)
Expand All @@ -976,21 +980,21 @@
self.detect_threshold_z = best_threshold
self._save_threshold(best_threshold, vars["speed"])

# Handle None for standard deviation by using a default message
std_dev_display = (
f"{best_result['standard_deviation']:.5f}"
if best_result["standard_deviation"] is not None
# Handle None for max deviation by using a default message
max_dev_display = (
f"{best_result['max_deviation']:.5f}"
if best_result["max_deviation"] is not None
else "N/A"
)

# Inform the user about the result
if optimal_found:
gcmd.respond_info(
f"Optimal Threshold Determined: {best_threshold} with standard deviation of {std_dev_display}"
f"Optimal Threshold Determined: {best_threshold} with max deviation of {max_dev_display}"
)
else:
gcmd.respond_info(
f"No fully optimal threshold found. Best attempt: {best_threshold} with standard deviation of {std_dev_display}"
f"No fully optimal threshold found. Best attempt: {best_threshold} with max deviation of {max_dev_display}"
)
gcmd.respond_info(
f"You can now {format_macro('SAVE_CONFIG')} to save your threshold."
Expand Down Expand Up @@ -1098,7 +1102,7 @@
f"Deviation: {deviation:.4f}\nNew Average: {average:.4f}\nTolerance: {tolerance:.4f}",
)

std_dev = np.std(samples) if samples else None
max_dev = np.std(samples) if samples else None
if len(samples) == num_samples:
success = True
position_difference = (
Expand All @@ -1111,7 +1115,7 @@
f"Position Difference: {position_difference:.4f}\nAdjusted Difference: {adjusted_difference:.4f}",
)
else:
std_dev = None
max_dev = None
success = False

self.toolhead.wait_moves()
Expand All @@ -1121,7 +1125,7 @@
# Return relevant data
return {
"samples": samples,
"standard_deviation": std_dev,
"max_deviation": max_dev,
"final_position": initial_position,
"retries": retries,
"success": success,
Expand Down Expand Up @@ -3248,7 +3252,7 @@
pa = (begin_a, pos_p) if even else (end_a, pos_p)
pb = (end_a, pos_p) if even else (begin_a, pos_p)

l = (pa, pb)

Check failure on line 3255 in scanner.py

View workflow job for this annotation

GitHub Actions / Standard Checks

Ruff (E741)

scanner.py:3255:13: E741 Ambiguous variable name: `l`

Check failure on line 3255 in scanner.py

View workflow job for this annotation

GitHub Actions / K1 Checks

Ruff (E741)

scanner.py:3255:13: E741 Ambiguous variable name: `l`

if len(points) > 0 and corner_radius > 0:
# We need to insert an overscan corner. Basically we insert
Expand Down
2 changes: 1 addition & 1 deletion scripts/firmware.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
ClassVar,
)

FLASHER_VERSION: str = "0.0.4"
FLASHER_VERSION: str = "0.0.5"

PAGE_WIDTH: int = 89 # Default global width

Expand Down
Loading