Skip to content

[BUG] Multiple probing >2 produces incorrect mesh (ProUI probe.cpp bug) #252

Description

@stratos1st

Did you test the latest release build?

Yes, and the problem still exists.

Bug Description

When multiple_probing >= 3, mesh values become incorrect (nozzle prints too high).
multiple_probing = 1–2 works correctly.
multiple_probing = 3–4 produces increasingly wrong results.

What i think is the problem:
The ProUI probe implementation incorrectly reuses the 2-probe weighting formula for N>2 samples, causing invalid mesh values.
A suggested fix is to branch logic for mp >= 3 and use averaging / filtering just like the nonProUI version.
I think the problem is in Marlin/src/module/probe.cpp line 1004

// Return a weighted average of the fast and slow probes
    const float measured_z = (TERN(PROUI_EX, PRO_data, HMI_data).multiple_probing > 1) ?
    (probes_z_sum * 3.0f + z1 * 2.0f) * 0.2f : z1;

I suggest something like this

    // Raise to give the probe clearance
    motion.do_z_clearance(z1 + (Z_CLEARANCE_MULTI_PROBE));

    const uint8_t mp = TERN(PROUI_EX, PRO_data, HMI_data).multiple_probing;

    float measured_z;

    if (mp <= 1) {

      // Single probing: just use the fast probe result
      measured_z = z1;

    }
    else if (mp == 2) {

      // One additional slow probe
      if (TERN0(PROBE_TARE, tare())) return NAN;

      if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Slow Probe:");
      if (try_to_probe(PSTR("SLOW"), z_probe_low_point, motion.z_probe_slow_mm_s, sanity_check)) return NAN;

      TERN_(MEASURE_BACKLASH_WHEN_PROBING, backlash.measure_with_probe());

      const float z2 = DIFF_TERN(HAS_DELTA_SENSORLESS_PROBING, motion.position.z, largest_sensorless_adj);

      if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("2nd Probe Z:", z2, " Discrepancy:", z1 - z2);

      // Keep the legacy fast/slow weighted average for 2 probes
      measured_z = (z2 * 3.0f + z1 * 2.0f) * 0.2f;

    }
    else {

      // 3+ probes: collect and sort all slow probes, then trim outliers
      float probes_z_sum = 0;
      float probes[10]; // enough for realistic UI-selected multiple probing counts

      const uint8_t slow_count = mp - 1;

      for (uint8_t p = 0; p < slow_count; p++) {
        if (TERN0(PROBE_TARE, tare())) return NAN;

        if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Slow Probe:");
        if (try_to_probe(PSTR("SLOW"), z_probe_low_point, motion.z_probe_slow_mm_s, sanity_check)) return NAN;

        TERN_(MEASURE_BACKLASH_WHEN_PROBING, backlash.measure_with_probe());

        const float z = DIFF_TERN(HAS_DELTA_SENSORLESS_PROBING, motion.position.z, largest_sensorless_adj);

        // Insert into probes[] in ascending order
        uint8_t i = 0;
        for (; i < p; ++i)
          if (probes[i] > z) break;

        for (int8_t m = p; m > (int8_t)i; --m)
          probes[m] = probes[m - 1];

        probes[i] = z;

        // Small Z raise after all but the last slow probe
        if (p < slow_count - 1)
          motion.do_z_clearance(z + (Z_CLEARANCE_MULTI_PROBE));
      }

      // Use the median of the slow probes to decide which values are outliers
      const uint8_t n = slow_count;
      const uint8_t half = (n - 1) / 2;
      const float middle = probes[half];
      const float median = (n & 1) ? middle : (middle + probes[half + 1]) * 0.5f;

      // Trim one outlier (the value farthest from the median) when possible
      uint8_t min_avg_idx = 0, max_avg_idx = n - 1;
      if (n > 2) {
        if (ABS(probes[max_avg_idx] - median) > ABS(probes[min_avg_idx] - median))
          max_avg_idx--;
        else
          min_avg_idx++;
      }

      for (uint8_t i = min_avg_idx; i <= max_avg_idx; ++i)
        probes_z_sum += probes[i];

      const uint8_t kept = max_avg_idx - min_avg_idx + 1;

      // Blend the fast probe with the filtered slow-probe average
      const float slow_avg = probes_z_sum / kept;
      measured_z = (slow_avg * 3.0f + z1 * 2.0f) * 0.2f;

    }

The only major issue with this is float probes[10];, currently the UI allows to set multiple_probing up to 4 so that will probably work for a while but i guess its bad practice to leave this value hard coded, thats why i didnt do a pull request with the suggested fix.

Firmware File

Aquila_N32_UBL-ProUI-EX-MPC-03-15.bin

Printer Model

Voxelab Aquila

Model Type

OG

Your Mainboard or Chipset

Aquila N32

Other Mainboard Type

No response

Add-ons that could be involved

BL

ProUI-EX | Extra Features?

Yes

Bed Leveling

UBL - Unified Bed Leveling

Did you include your own configuration files?

  • A ZIP file containing your Configuration.h and Configuration_adv.h.

Additional information & file uploads

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwork-in-progressCurrently focused on this issue

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions