Skip to content

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

@stratos1st

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

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