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

V2.0 of UBL now available #4828

Closed
Roxy-3D opened this issue Sep 18, 2016 · 133 comments
Closed

V2.0 of UBL now available #4828

Roxy-3D opened this issue Sep 18, 2016 · 133 comments

Comments

@Roxy-3D
Copy link
Member

Roxy-3D commented Sep 18, 2016

Many small fixes for annoying issues, including the z_offset problem.

Most of the changes are for the purpose of speeding up the code paths in preparation for bringing the UBL system up on Delta printers.

You can get it here: https://github.com/MarlinFirmware/Marlin/tree/devel-ubl

@kmbecker13
Copy link

Great! @Roxy-3D Quick question on the G29 P3 command...is that required for a successful mesh? I'm somewhat confused on what areas it fills in, is it the edges of the bed or areas that may not have been probed during the P2?

Haven't been using it and am curious if i should be. My current process is to do a G29 P1, then P2 to get the un-probable areas and then right into a G26 to see how it looks. G29 P4 from there as needed based on the G26.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

I'm on the way out the door... But the quick answer is nothing is required. If you have unprobed mesh points, the system will default those to 0.0000 However, you should fill in the mesh points one way or the other. You can Manually Probe or you can fill with a constant (P2 and P3)

What you really want to do is get to the point where you can do a G26 across the entire bed, because that lets you use the built in Mesh Editor (G29 P4 R M)

With that, you can get the Mesh perfect in 1 or 2 iterations.

(Be sure to save your perfect mesh with a G29 S1 (or some suitable number) so it is available for use later!)

@kmbecker13
Copy link

Thanks @Roxy-3D - playing with this now and it seems like the global variables use over 100% of dynamic memory available (8202 bytes)? I think i might be missing something so i'll hold off on making a new issue for this..

@printerguykw
Copy link

#awesome, going to try this version soon.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

playing with this now and it seems like the global variables use over 100% of dynamic memory available (8202 bytes)?

I can't say without doing some work... But that surprises me. I did bump up the depth of the planner block buffer from 16 moves to 32 moves deep. At least with a 20x4 LCD display, there should be just under 2KB of RAM free. If you have a graphics display, you may need to move that back down to 16 deep. (It is in Configuration_adv.h)

(These Graphic displays are a nuisance! They burn up the CPU and they eat up memory. )

If you can't link and flash because you are out of memory... Please change these lines (in Configuration_adv.h) back to this:

// The number of linear motions that can be in the plan at any give time.
// THE BLOCK_BUFFER_SIZE NEEDS TO BE A POWER OF 2, i.g. 8,16,32 because shifts and ors are used to do the ring-buffering.
#if ENABLED(SDSUPPORT)
  #define BLOCK_BUFFER_SIZE 16   // SD,LCD,Buttons take more memory, block buffer needs to be smaller
#else
  #define BLOCK_BUFFER_SIZE 16 // maximize block buffer
#endif

When I get confirmation that lets you continue, I'll update the main code base to make that the default.

@kmbecker13
Copy link

Yep that worked, with a 7 x 7 mesh i still have over 1KB of free RAM and it compiled!

However i had to select 1 extruder to get it to compile instead of my normal 2 (it gave another error saying "Marlin_main.cpp:6298: error: 'fade_scaling_factor_for_Z' was not declared in this scope" when i try to use 2 extruders)

@adamfilip
Copy link

I had to set buffer back to 16
at 32 it only had 6 bytes free

@adamfilip
Copy link

@Roxy-3D im Running a G29 P1 M now, ive noticed it still pausing once in a while. for what feels like 30 seconds.
think this is buffer or free memory related?

@kablam
Copy link

kablam commented Sep 18, 2016

I'm getting this when i try to compile in latest arduino software.

Arduino:1.6.11 (Windows 10), Kort:"Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

sketch\Marlin_main.cpp: In function 'void gcode_M47()':

Marlin_main.cpp:3672: error: 'blm' was not declared in this scope

  xi = blm.get_cell_index_x(x);
       ^

sketch\Marlin_main.cpp: In function 'void process_next_command()':

Marlin_main.cpp:6461: error: 'gcode_G25' was not declared in this scope

           gcode_G25();
                     ^

exit status 1
'blm' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

I had to set buffer back to 16 at 32 it only had 6 bytes free

OK... The default setting is back at 16. That really should be enough. I did some timing tests to see what was going on and most of the time is spent waiting for the buffer to open up so another move can be put in the list. In other words, most of the time the system is deep inside the planner calling idle() while it waits for room.

i'm Running a G29 P1 M now, i've noticed it still pausing once in a while. for what feels like 30 seconds. think this is buffer or free memory related?

I've never seen it do that during a P1. Does it do it without the M option? I'm wondering if it is a communication problem and you are waiting for some time out condition to happen and then the serial link recovers? You can rule out free memory issues by initializing the M100 Free Memory Watcher prior to do the G29 P1 M and then ask it to give you the Memory Statistics after the G29 P1 M completes. As long as there is stack space free, it isn't a free memory related issue.

i'm getting this when i try to compile in latest arduino software.
@kablam gcode_G25() is for Delta's to help physically level the bed. It was working in previous versions of my code, but I'm pretty sure it is going to need to be brought up to date because of all the changes to Marlin's lower level planner and stepper code. Can you attach your Configuration.h file and I'll duplicate the problem and remove the dependency. I can tell you it should not be getting pulled into the compilation unless you are on a Delta. And I have not even started the work to get Delta's going yet (but I'm close to doing that).

@adamfilip
Copy link

Weird result when generating mesh.. see image.. started raising Z gantry alot
ubl-mesh-test

But some good news.. I reran my M48 V4 P10 with my Hinged Z probe and here are my results :)

READ: Mean: -0.997358
READ: Standard Deviation: 0.000677

@adamfilip
Copy link

adamfilip commented Sep 18, 2016

Video showing pauses
https://youtu.be/Hm4IM9pzTV4

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

But some good news.. I reran my M48 V4 P10 with my Hinged Z probe and here are my results :)
READ: Mean: -0.997358
READ: Standard Deviation: 0.000677

That -86.22 is concerning. I'm just using the standard probe_pt() routine. There isn't much math that can be doing that in the UBL code. One thing I can do is add some sanity checks to make sure the numbers are plausible.

It looks like you should shift your Z_PROBE_OFFSET_FROM_EXTRUDER by 1.0 mm But that Standard Deviation of .0007mm is very good, especially since the whole nozzle mechanism is moving and having to come back into position.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

However i had to select 1 extruder to get it to compile instead of my normal 2 (it gave another error saying "Marlin_main.cpp:6298: error: 'fade_scaling_factor_for_Z' was not declared in this scope" when i try to use 2 extruders)

@kmbecker13 I'll see if I can resolve the multiple extruder issue this morning. It shouldn't be too big of a deal to get that turned back on and working. The bigger issue is there has been ZERO testing of multiple extruders within UBL. So keep an eye on it and make sure it is behaving correctly once I get it to compile clean.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

@kmbecker13 If you pull down the latest code... It should compile with multiple extruders enabled.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

Video showing pauses https://youtu.be/Hm4IM9pzTV4

@adamfilip Wow! That is a nice machine! Its bed is huge. I see why you want to use a large mesh to level it!

The interesting thing in that video at about 1:08 is it pauses after the first trigger of the probe. It pauses before it does the 2nd, slower speed measurement. That implies it is in the middle of the probe_pt() routine when it happens. I think that rules out a communication issue because there is no chit chat between Marlin and the host at that point. (At least, that is my best guess but there is a Verbose level passed into probe_pt() )

How often does this pause happen? It would be nice if it happens every time you do a G29 P1. But here is something else that I'm wondering about. Under certain conditions the probe_pt() routine will return Not-a-Number. That happens when it has problems deploying or stowing the probe. I'm wondering if that is where that crazy -86.22 number came from. I'm wondering if that number is not being interpreted correctly.

We have a couple of options. One option is to turn on the DEBUG_LEVELING_FEATURE to get more information. We can also uncomment the various Checkpoint # messages so we see how far through the probe_pt() routine it is getting. With the extra information, that should narrow the field of things for us to look at to find the problem.

I haven't dug in to understand things yet. But you have a very special probe. Besides triggering at a positive Z_PROBE_OFFSET_FROM_EXTRUDER number, you don't have any stow or deploy action. I'm wondering if we are going to find there is some thing unanticipated. Once we see how far into probe_pt() it is getting before the pause happens... Things will start to make sense.

    #endif
    feedrate = XY_PROBE_FEEDRATE;
//SERIAL_PROTOCOLPGM("Checkpoint #0\n");
    do_blocking_move_to_xy(x - (X_PROBE_OFFSET_FROM_EXTRUDER), y - (Y_PROBE_OFFSET_FROM_EXTRUDER));
//SERIAL_PROTOCOLPGM("Checkpoint #1\n");

    #if ENABLED(DEBUG_LEVELING_FEATURE)
      if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
    #endif
//SERIAL_PROTOCOLPGM("Checkpoint #2\n");
    if (DEPLOY_PROBE()) return NAN;
//SERIAL_PROTOCOLPGM("Checkpoint #3\n");

    float measured_z = run_z_probe();
//SERIAL_PROTOCOLPGM("Checkpoint #4\n");

    if (stow) {
      #if ENABLED(DEBUG_LEVELING_FEATURE)
        if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
      #endif
      if (STOW_PROBE()) return NAN;
    }
    else {
      #if ENABLED(DEBUG_LEVELING_FEATURE)
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> do_probe_raise");
      #endif
//SERIAL_PROTOCOLPGM("Checkpoint #5\n");
      do_probe_raise(Z_RAISE_BETWEEN_PROBINGS);
    }
//SERIAL_PROTOCOLPGM("Checkpoint #6\n");

@adamfilip
Copy link

I set it up to 5x5 grid because its faster lol.
I was able to do the full grid.. without any manual entry needed Woohoo! (Helps that I have 0 XY probe offset)
with a 5x5 i didnt run into pauses, maybe it uses less memory and that helps
I ran a M100 I before and M100 F after
Before the G29 P1 M free memory was 1748 b and after it was 1384 b, and thats only a 5x5 grid

i believe the pausing is related to the weird numbers.. seems like after it pauses they start to occur
ubl-screen-2

@adamfilip
Copy link

Wow! That is a nice machine! Its bed is huge.

@Roxy-3D Thanks!, and i will be increasing it to 300x600 soon too.. so i really need to get the UBL working :)

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

with a 5x5 i didnt run into pauses, maybe it uses less memory and that helps

5x5 will use less memory. But as long as there is enough free memory, it shouldn't matter how much memory is free. Each location uses 4 bytes. So a 10x10 will consume 400 bytes of memory. A 5x5 will only eat up 100 bytes.

I ran a M100 I before and M100 F after Before the G29 P1 M free memory was 1748 b and after it was 1384 b, and thats only a 5x5 grid.

So... you should still be over a 1KB of free memory with a 10x10. I don't think it is free memory that is causing problems. Instead... with a bigger mesh, you are probing more points. It maybe the bigger mesh just gives more opportunity for the problem to manifest itself.

i believe the pausing is related to the weird numbers.. seems like after it pauses they start to occur

This is very possible. Especially because there are error conditions where I have it returning NAN. But if that is the case, there is something else going on. The reason I say that is once a number becomes NAN, it should propagate through further computations. Officially, you are only supposed to have to check for NAN at the very end of calculations. (I'm not sure I check at all, but the SERIAL_OUTPUT routines should print out NAN. I'll have to verify that.) And very literally, those '.' in the map are NAN values. If the probe_pt() routine returns NAN and ultimately the number gets stored in the Mesh, it should still be NAN. It should display as '.' I'm sure it will all make sense once we figure it out. But right now, I'm not sure what is going on.

I think we may be running into an issue in the stow or deploy routines. Let's get the extra debug stuff turned on and see where the pause happens.

@adamfilip
Copy link

ok i set it back to a 10x10 and the errors
problem started happening after 20 probings
i enabled all checks.. and it seemed to start hanging on check 3

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

Did you notice you have a couple of outlier points on the left side? (of the 5x5 Mesh) At the top left, you have 1.2mm surrounded by almost 0.0 numbers. I wonder if that is an issue with the bed wrapping at a mounting point? And then lower down on the left side you have a -.72 number with a .404 number right next to it.

I think you would benefit from going even higher than a 10x10 Mesh.

@adamfilip
Copy link

here is the 10x10 i just did
20160918_114908

@adamfilip
Copy link

it started with the -2.14591 in upper right

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

i enabled all checks.. and it seemed to start hanging on check 3

//SERIAL_PROTOCOLPGM("Checkpoint #2\n");
    if (DEPLOY_PROBE()) return NAN;
//SERIAL_PROTOCOLPGM("Checkpoint #3\n");
    float measured_z = run_z_probe();
//SERIAL_PROTOCOLPGM("Checkpoint #4\n");

So... It is inside of run_z_probe() when it pauses. I guess we should modify run_z_probe() to have lots of check point info so we can see where in it the problem happens. Can you put similar lines of code every couple lines in run_z_probe() ? Just add your own flavor of message:

SERIAL_PROTOCOLPGM("in run_z_probe() #1\n");

at various points?

@adamfilip
Copy link

adamfilip commented Sep 18, 2016

I added a bunch of comments but now im getting a compile error
"expected constructor, destructor, or type conversion before '(' token"

#define SERIAL_PROTOCOLPGM(x) serialprintPGM(PSTR(x))

here is the code i added comments too

//      #if ENABLED(UNIFIED_BED_LEVELING_FEATURE)
//        planner.bed_level_matrix.set_to_identity();
//      #endif

      feedrate = homing_feedrate[Z_AXIS];

      // Move down until the Z probe (or endstop?) is triggered
SERIAL_PROTOCOLPGM("in run_z_probe() #A Move down until the Z probeis triggered\n");
      float zPosition = -(Z_MAX_LENGTH + 10);
      line_to_z(zPosition);
      stepper.synchronize();

      // Tell the planner where we ended up - Get this from the stepper handler
SERIAL_PROTOCOLPGM("in run_z_probe() #B Tell the planner where we ended up\n");
      zPosition = stepper.get_axis_position_mm(Z_AXIS);
      planner.set_position_mm(
        current_position[X_AXIS], current_position[Y_AXIS], zPosition,
        current_position[E_AXIS]
      );

      // move up the retract distance
SERIAL_PROTOCOLPGM("in run_z_probe() #C move up the retract distance\n");
      zPosition += home_bump_mm(Z_AXIS);
      line_to_z(zPosition);
      stepper.synchronize();
      endstops.hit_on_purpose(); // clear endstop hit flags

      // move back down slowly to find bed
SERIAL_PROTOCOLPGM("in run_z_probe() #D move back down slowly to find bed\n");
      set_homing_bump_feedrate(Z_AXIS);

      zPosition -= home_bump_mm(Z_AXIS) * 2;
      line_to_z(zPosition);
      stepper.synchronize();
      endstops.hit_on_purpose(); // clear endstop hit flags

      // Get the current stepper position after bumping an endstop
SERIAL_PROTOCOLPGM("in run_z_probe() #E Get the current stepper position after bumping an endstop\n");
      current_position[Z_AXIS] = stepper.get_axis_position_mm(Z_AXIS);

      #if ENABLED(DEBUG_LEVELING_FEATURE)
        if (DEBUGGING(LEVELING)) DEBUG_POS("run_z_probe", current_position);
      #endif

    #endif // !DELTA

    SYNC_PLAN_POSITION_KINEMATIC();

    feedrate = old_feedrate;

    return current_position[Z_AXIS];
  }
SERIAL_PROTOCOLPGM("in run_z_probe() #F\n");
void do_blocking_move_to_xy(float x, float y, float feed_rate) {
    do_blocking_move_to(x, y, current_position[Z_AXIS], feed_rate);
  }
SERIAL_PROTOCOLPGM("in run_z_probe() #G\n");
  //
  // - Move to the given XY
  // - Deploy the probe, if not already deployed
  // - Probe the bed, get the Z position
  // - Depending on the 'stow' flag
  //   - Stow the probe, or
  //   - Raise to the BETWEEN height
  // - Return the probed Z position
  //
float probe_pt(float x, float y, bool stow, int verbose_level) {
    #if ENABLED(DEBUG_LEVELING_FEATURE)
      if (DEBUGGING(LEVELING)) {
        SERIAL_ECHOPAIR(">>> probe_pt(", x);
        SERIAL_ECHOPAIR(", ", y);
        SERIAL_ECHOPAIR(", ", stow ? "stow" : "no stow");
        SERIAL_ECHOLNPGM(")");
        DEBUG_POS("", current_position);
      }
    #endif
SERIAL_PROTOCOLPGM("in run_z_probe() #H\n");

    float old_feedrate = feedrate;

    // Ensure a minimum height before moving the probe
    do_probe_raise(Z_RAISE_BETWEEN_PROBINGS);
SERIAL_PROTOCOLPGM("in run_z_probe() #I \n");

    // Move to the XY where we shall probe
    #if ENABLED(DEBUG_LEVELING_FEATURE)
      if (DEBUGGING(LEVELING)) {
        SERIAL_ECHOPAIR("> do_blocking_move_to_xy(", x - (X_PROBE_OFFSET_FROM_EXTRUDER));
        SERIAL_ECHOPAIR(", ", y - (Y_PROBE_OFFSET_FROM_EXTRUDER));
        SERIAL_ECHOLNPGM(")");
      }
    #endif
SERIAL_PROTOCOLPGM("in run_z_probe() #J\n");
    feedrate = XY_PROBE_FEEDRATE;
SERIAL_PROTOCOLPGM("Checkpoint #0\n");
    do_blocking_move_to_xy(x - (X_PROBE_OFFSET_FROM_EXTRUDER), y - (Y_PROBE_OFFSET_FROM_EXTRUDER));
SERIAL_PROTOCOLPGM("Checkpoint #1\n");

    #if ENABLED(DEBUG_LEVELING_FEATURE)
      if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
    #endif
SERIAL_PROTOCOLPGM("Checkpoint #2\n");
    if (DEPLOY_PROBE()) return NAN;
SERIAL_PROTOCOLPGM("Checkpoint #3\n");

    float measured_z = run_z_probe();
SERIAL_PROTOCOLPGM("Checkpoint #4\n");

    if (stow) {
      #if ENABLED(DEBUG_LEVELING_FEATURE)
        if (DEBUGGING(LEVELING)) SERIAL_ECHOPGM("> ");
      #endif
      if (STOW_PROBE()) return NAN;
    }
    else {
      #if ENABLED(DEBUG_LEVELING_FEATURE)
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> do_probe_raise");
      #endif
SERIAL_PROTOCOLPGM("Checkpoint #5\n");
      do_probe_raise(Z_RAISE_BETWEEN_PROBINGS);
    }
SERIAL_PROTOCOLPGM("Checkpoint #6\n");

    if (verbose_level > 2) {
      SERIAL_PROTOCOLPGM("Bed X: ");
      SERIAL_PROTOCOL_F(x, 3);
      SERIAL_PROTOCOLPGM(" Y: ");
      SERIAL_PROTOCOL_F(y, 3);
      SERIAL_PROTOCOLPGM(" Z: ");
      SERIAL_PROTOCOL_F(measured_z, 3);
      SERIAL_EOL;
    }

    #if ENABLED(DEBUG_LEVELING_FEATURE)
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< probe_pt");
    #endif

    feedrate = old_feedrate;

    return measured_z;
  }

#endif // HAS_BED_PROBE

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

The macro expansion of SERIAL_PROTOCOLPGM("something_here"); is very sensitive to mistakes.

The SERIAL_PROTOCOLPGM("in run_z_probe() #G\n"); line looks like it is outside of a function. If so, that will cause a compiler error.

If you still have problems after fixing that... I'll add debug code to the run_z_probe() routine and you can just cut and paste it from here into Marlin_main.cpp. I thought it would be easier to just have you put the debug lines in. If not, we can do it the other way.

@adamfilip
Copy link

ok well i screwed up something lol.. gotta start from scratch.. download the firmware again..
best to not let me make changes to code lol

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 18, 2016

ok well i screwed up something lol.. gotta start from scratch.. download the firmware again..
best to not let me make changes to code lol

These are simple changes... We should be able to get them in place without too much of a problem. Just be careful, because we don't want any 'unknown' changes! We really don't have a choice. We have to debug this on your hardware because it seems that is the only place the problem shows up.

And remember... There is a fall back position. Even if we can't figure out where the probe_pt() routine is failing, we can do a G29 P0 to zero the entire mesh, and jump straight to the G26 C P O2.5 The first iteration will probably produce a horrible Mesh Validation pattern, but at that point, you can edit it and start pushing and pulling on the Mesh points. In theory, you don't even have to automatically probe the bed.

@adamfilip
Copy link

I wonder if my rumba is glitchy. I am getting issues sometimes connecting and I need to run at 115200 baud serial

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 26, 2016

OK! I found an 'off by one' error that was affecting the last segment of moves. It should print much cleaner now. Please give it a try.

I've added some 'Sanity Check' code that should never trigger if everything checks out. If you see some messages with coordinates and z_optimized in them come out on the serial console, I need to know what gets said. But hopefully that code never prints anything and I delete it soon!

The 'M' option has been converted to 'O' and 'Q' in G29 and G26 respectively. But other than that, it is ready to give it a test. I think it is going to be much better behaved now. However, because the Z Correction was off on the final segment of the nozzle move, you probably have to do a G26 Mesh Validation Pattern and then go back and do a G29 P4 R to edit any areas that are not perfect. Then... You will be ready for a real print.

@adamfilip No, I haven't looked at it. But I really should! Have you tried it? What do you like and dislike about his version?

@thinkyhead You like doing optimizations! You might want to skim this PS: message.

PS. When ever I hear somebody had an 'Off by one' error, I wince and ask "How hard can it be to get the edge conditions right?" Well... This stuff gets confusing! Here is where the problem was:

    FINAL_MOVE:
        a0ma1diva2ma1 = (x_end - mesh_index_to_X_location[cell_dest_xi]) * (float) (1.0 / MESH_X_DIST);

        z1 = z_values[cell_dest_xi][cell_dest_yi] +
            (z_values[cell_dest_xi + 1][cell_dest_yi] - z_values[cell_dest_xi][cell_dest_yi]) * a0ma1diva2ma1;

        z2 = z_values[cell_dest_xi][cell_dest_yi+1] +
            (z_values[cell_dest_xi+1][cell_dest_yi+1] - z_values[cell_dest_xi][cell_dest_yi+1]) * a0ma1diva2ma1;

        // we are done with the fractional X distance into the cell.  Now with the two Z-Heights we have calculated, we 
        // are going to apply the Y-Distance into the cell to interpolate the final Z correction.

        a0ma1diva2ma1 = (y_end - mesh_index_to_Y_location[cell_dest_yi]) * (float) (1.0 / MESH_Y_DIST);

        z0 = z1 + (z2 - z1) * a0ma1diva2ma1;

And for the record... The original Mesh Leveling routines worked well! But if you count the floating point operations (and also factor in the reductions of floating point divides) compared to the original code, this new code frees up a bunch of CPU cycles to help the Delta's. (Be sure to account for the compiler 'folding constants' if you do the count. The preprocessor is going to turn the 1.0/MESH terms into a simple float that can be used at exectution time.) In a nut shell, the new code is replacing a call to get_z_correction( x_end, y_end);

inline float calc_z0(float a0, float a1, float z1, float a2, float z2) {
      float delta_z = (z2 - z1);
      float delta_a = (a0 - a1) / (a2 - a1);
      return z1 + delta_a * delta_z;
    }

FORCE_INLINE float map_x_index_to_bed_location(int8_t i){ return ((float) MESH_MIN_X) + (((float) MESH_X_DIST) * (float) i); };
FORCE_INLINE float map_y_index_to_bed_location(int8_t i){ return ((float) MESH_MIN_Y) + (((float) MESH_Y_DIST) * (float) i); };
int8_t get_cell_index_x(float x) {
      int8_t cx = (x - (MESH_MIN_X)) * (1.0 / (MESH_X_DIST));
      return constrain(cx, 0, (MESH_NUM_X_POINTS) - 1); 
    }                       
int8_t get_cell_index_y(float y) {
      int8_t cy = cy = (y - (MESH_MIN_Y)) * (1.0 / (MESH_Y_DIST));
      return constrain(cy, 0, (MESH_NUM_Y_POINTS) - 1); 
    }           
//
//  This is the generic Z-Correction.  It works anywhere within a Mesh Cell.  It first
//  does a linear interpolation along both of the bounding X-Mesh-Lines to find the
//  Z-Height at both ends.  Then it does a linear interpolation of these heights based
//  on the Y position within the cell.
//
    float get_z_correction(float x0, float y0) {
      int8_t cx = get_cell_index_x(x0),
             cy = get_cell_index_y(y0);
      float z1 = calc_z0(x0,
                    map_x_index_to_bed_location(cx), z_values[cx][cy],
                    map_x_index_to_bed_location(cx + 1), z_values[cx + 1][cy]);
      float z2 = calc_z0(x0,
                   map_x_index_to_bed_location(cx), z_values[cx][cy + 1],
                   map_x_index_to_bed_location(cx + 1), z_values[cx + 1][cy + 1]);
      float z0 = calc_z0(y0,
                   map_y_index_to_bed_location(cy), z1,
                   map_y_index_to_bed_location(cy + 1), z2);

     if ( isnan(z0) ) {     // if part of the Mesh is undefined, it will show up as NAN
       z0 = 0.0;        // in blm.z_values[][] and propagate through the 
                // calculations. If our correction is NAN, we throw it out 
                // because part of the Mesh is undefined and we don't have the 
                // information we need to complete the height correction.
     }
     return z0;         // there used to be a  +state.z_offset on this line
  }

@kmbecker13
Copy link

I've got a Prusa Mk2 and really like the firmware as well. It was the main reason i started looking for better solutions for my other printer (i.e UBL) since it worked so well. Some things i like about it are:

  • auto axis skew correction by measuring 9 pre-placed points on the bed (probably not possible without their Mk42 bed, or something similar, in Marlin)
  • live z-adjust gets stored as the z-offset in the firmware, i don't believe UBL currently does this (tho it's close!). From my understanding, with UBL you still need to adjust the "Bed Z offset" under "Tune" to store the new z offset (and this isn't a 'live' change, meaning it wont affect layers that are currently printing).
  • Overall, it works very well and gets the bed extremely level without any fuss.

@adamfilip
Copy link

I will be able to test it in a few days. once i get my corexy machine back together.. took it apart to add some nice upgrades (Linear Guides!)

@kmbecker13
Copy link

kmbecker13 commented Sep 26, 2016

@Roxy-3D Just tested the new code and it seems pretty good! No z-hop seen yet. I've noticed that when i do the G26 it isn't always exiting when i hold the knob down, it takes quite a few tries for it to register the cancel command.

Also, this may be a dumb question - but the G29 Z # command is sending an absolute command for the offset, not a relative change, correct?

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 26, 2016

@Roxy-3D Just tested the new code and it seems pretty good! No z-hop seen yet. I've noticed that when i do the G26 it isn't always exiting when i hold the knob down, it takes quite a few tries for it to register the cancel command.

The Encoder Wheel is only checked once per Mesh Point Circle and connecting lines. You need to have the Encoder Wheel pressed when it starts to draw the next circle for it to be detected. I guess I could check more often than that, but right now, that is what it does. Are you not seeing that behavior?

Also, this may be a dumb question - but the G29 Z command is sending an absolute command for the offset, not a relative change, correct?

There are two flavors of G29 Z. One with no number in which case it probes to find the offset. And there is the version where you can say G29 Z 1.23 and specify a number to apply. Both of those versions assign a value to z_offset (that gets reported with a G29 W or when the EEPROM loads.) That number is absolute in the sense, it is what it is. But that number gets added onto any Z coordinate that gets sent to the planner. So in that sense, it is relative. I think there is still a bug in how the Z-Offset is used elsewhere in the code because of things Adamfilip said. I'm almost set to go look for that. But I've been entirely focused on that weird movement problem. Now that I think that is fixed, I can look at getting the Z-Offset to behave how people expect it to act.

@kmbecker13
Copy link

kmbecker13 commented Sep 26, 2016

Gotcha - i should explain what i mean/am experiencing. After building a mesh, i did a G29 P2 and G29 Z to get my height correct, but during a G26 I noticed that my nozzle was about .1-.2mm too high. I cancelled the G26 and then thought id lower my nozzle by .1 to see if that helped. I entered G29 Z -.1 and tried another G26, but it was still too high. After cancelling that, i did another G29 Z -.1

Does this mean my offset is now -.2 or was i setting it twice at -.1? If it's the second one, how can i check my current Z-offset before adjusting it at a new height (so i can increase by a known height)?

It would be fantastic if babystepping was enabled during the G26 to live adjust the z-offset. This is one of the key parts of the Prusa Mk2 calibration routine, after building a mesh you print a calibration gcode while live adjusting the z-height until it looks good. If you could get that functionality in G26, it would be awesome.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 26, 2016

Does this mean my offset is now -.2 or was i setting it twice at -.1?

No... The G29 Z's should not be cumulative. Only the last one will be effective. But one of the things to do on my list (with regard to the Z-Offset issue) is verify that + and - is consistent everywhere. If it is not, that would explain some of the issues adamfilip is reporting.

It would be fantastic if babystepping was enabled during the G26 to live adjust the z-offset. This is one of the key parts of the Prusa Mk2 calibration routine, after building a mesh you print a calibration gcode while live adjusting the z-height until it looks good. If you could get that functionality in G26, it would be awesome.

I guess that could be done. But maybe as an option. The problem with having it live all the time is when the Mesh Validation Pattern is complete, how are you going to remember "This part was drawn before I started Baby Stepping the nozzle down". The whole purpose of the Mesh Validation Pattern is to give you a recorded history of what the Mesh Values produce so that you can edit them up or down easily.

With that said, the Z-BabyStepping is live when the print starts. And with the QUICK_ACCESS_TO_Z_BABYSTEPPING you can instantly get to it and shift the nozzle. I really don't use it. Even with my horrible piece of glass I'm using for the UBL Development, I don't have to adjust the nozzle.

@kmbecker13
Copy link

kmbecker13 commented Sep 27, 2016

Yea for me, the z-babystepping is more of a method to get the height offset perfect. I understand how it would skew results for the G26 mesh validation, perhaps a different print pattern could be used for the live height adjustment feature (maybe one that's a little shorter). It can be tough to get the height tuned perfectly with the currently G29 Z # command. What command will return my current z offset? Want to use a command to check my current Z offset before assigning a new one.

I've also noticed that at the end of a G26 on my printer, the LCD is unresponsive and frozen for some reason - so i can't go into the Motion menu to check the offset there.

Here is what i do on my Mk2 and it works super well: https://youtu.be/q_LqgABOICQ?t=40s

I envision that a user would use this after building a mesh to get a good height offset before they step into a full blown G26 to fine tune the mesh even further. Prusa doesn't currently have the ability to tune the mesh, so you have to just hope it's perfect - you have a major advantage in that regard :)

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 27, 2016

Yea for me, the z-babystepping is more of a method to get the height offset perfect. I understand how it would skew results for the G26 mesh validation, perhaps a different print pattern could be used for the live height adjustment feature (maybe one that's a little shorter).

It is very important to have the various Mesh Points accurately defined. Shifting the offsets and such during a calibration print seems akin to putting your thumb on a scale when trying to weight out a measure of meat. I suggest you don't do that. The whole purpose of G26 is to see if what areas of your mesh are good, and which ones need to be adjusted.

It can be tough to get the height tuned perfectly with the currently G29 Z # command. What command will return my current z offset? Want to use a command to check my current Z offset before assigning a new one.

G29 W will tell you the current Z-Offset. Also, an M503 will tell you the current settings.

I've also noticed that at the end of a G26 on my printer, the LCD is unresponsive and frozen for some reason - so i can't go into the Motion menu to check the offset there.

I have not seen any problems with the LCD Panel being frozen. But still, what ever the Z-Offset is, you can save it. It is part of the UBL State Information. Just do a G29 S5 and it will save the current Mesh and State Information.

Here is what i do on my Mk2 and it works super well: https://youtu.be/q_LqgABOICQ?t=40s

Interesting! I'm in competition with Prusa!

I envision that a user would use this after building a mesh to get a good height offset before they step into a full blown G26 to fine tune the mesh even further. Prusa doesn't currently have the ability to tune the mesh, so you have to just hope it's perfect - you have a major advantage in that regard :)

I see it differently. The better you square your axis's and the better you get all of your mechanical movements on the printer to 'Repeat', the more hope you have for a high quality 3D-Printer. (I know we are not arguing about this. I'm just trying to communicate my thought process.)

The Auto Bed Alignment is really best used to address flaws in the mechanical setup of the printer. The 'less work' the Auto Bed Leveling System needs to do, the better your printing experience will be. With that said, it is my goal to make the UBL System accommodate even a poorly calibrated Delta. It shouldn't be used that way. But I want to make it capable of being used that way.

The G26 Mesh Validation Pattern is a low level tool that graphically shows you the relationship between your bed and the nozzle at each 'Mesh Point'. We don't want to hide or correct that. We want this information to be accurate so we can use it to Edit the Mesh to be 'correct'.

I'm starting to think we should simplify things (for the user) and eliminate the z_offset. Please join the discussion or contribute to this thread: #4908

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 27, 2016

I envision that a user would use this after building a mesh to get a good height offset before they step into a full blown G26 to fine tune the mesh even further. Prusa doesn't currently have the ability to tune the mesh, so you have to just hope it's perfect - you have a major advantage in that regard :)

Or... How about this: What if we provided an option or a GCode command that is put in your startup code for the Slic3r. Just like you put a G28 in there, you would put this command in place after the G28, G29 sequence. This new command would generate a higher precision pattern with the Z Baby Stepping already turned on. Probably something like a Spiral pattern starting at the center of the bed would make sense. The user could just dial in the exact height (using the Z-Baby-Stepping). The command would continue at a much higher speed than the Mesh Validation Pattern is drawn. It would keep working its way outward from the center until the user had confidence everything was working right, and then be terminate with a 'Press and Hold' of the Encoder Wheel.

There would not be much material put down on the bed. The user would just let the print start normally and print right on top of the Z-Baby-Step pattern.

@kmbecker13
Copy link

That sounds VERY good! As of right now, i'm actually doing G28, G29 and then doing a 1 layer test print to get my height offset dialed in. Once i have my height pretty close, then i go into a G26.

What you described would be very handy!

@thinkyhead
Copy link
Member

thinkyhead commented Sep 27, 2016

@Roxy-3D Is that "P.S. comment" applicable to the code here? What changes are you suggesting? (I'm a little slow today, otherwise I'd make sense of it.)

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 27, 2016

Is that "P.S. comment" applicable to the code here? What changes are you suggesting?

I'm not really suggesting any changes to the current code. The problem is the generic float get_z(float x0, float y0) has to get both the X & Y cell index which each involve a floating point divide (probably optimized to be a floating point multiply). It then does three float z1 = calc_z0(a0, a1, z1, a2, z2) calculations. And each of those calc_z0()'s does four floating point add's and a floating point multiply and (Gasp!!!!) a floating point divide.

That has to happen on each and every get_z() correction which happens at every Mesh Line. What I did was get the starting X & Y cell, and the ending X & Y cell just once for the entire buffer line. Most moves are within the same cell in which case the code I quoted up above comes into play. That code is much cheaper to do computationally.

But there are optimizations for the lines that cross cell boundaries. In the case of horizontal or vertical (Y direction) moves where you stay in the same column or row, the math gets simpler because you already know which Mesh Line you are crossing and the Z correction becomes a single interpolation instead of a bi-linear interpolation. (bi-linear requires 3 interpolations. 1 for each end of the line and then 1 to get the point in between the 2 calculated points.) And even the generic move which crosses both columns and rows is simplified by using the Mesh Line indexes to break the line up into segments. In that case the number of floating point operations only gets cut in half, but it is still worth doing.

Mostly... These changes are aimed at getting back a few CPU cycles for the Delta's! They aren't really needed for the Cartesian printers. But it is certainly easier to debug the code on a Cartesian printer!

@kmbecker13
Copy link

@Roxy-3D i'm still seeing the LCD freeze after starting a G26. It happens right when both extruder and bed reach temperature and only clears if i disconnect or reset power. Think its something related to the full graphics display?

I can continue to issue commands through my desktop application, but the LCD doesn't respond.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 28, 2016

i'm still seeing the LCD freeze after starting a G26. It happens right when both extruder and bed reach temperature and only clears if i disconnect or reset power. Think its something related to the full graphics display?

It may be related to the Graphics display. I do know there is code to periodically re-initialize the LCD Displays. That isn't being done because the LCD Displays are 'stable'. I'm going to be messing around in the LCD code over the next couple of days because I'm going to add detection for 'Press & Hold of the Encoder Wheel' to get it into Z-Baby-Step mode. In fact, that detection logic is going to be in the same routine where the periodic refresh of the display happens. So, I'll keep my eye out for things.

At worst case, I might have to put a Graphics Display onto my machine. I'm hoping it doesn't come to that.

@kmbecker13
Copy link

If you decide to get one, i'll split the cost with you if you have a way for me to contribute to your developing efforts 😄

@kmbecker13
Copy link

So as my LCD freezes after doing the G26, i've been disconnecting and reconnecting to regain functionality. Before i do this, i typically save my mesh and then reload it. I've noticed that when doing a G29 W before and after disconnecting, my z-offset appears to be lost during the disconnect.

Am i forgetting to do something to save this to the EEPROM? I've done an M500 as well.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 28, 2016

If you decide to get one, i'll split the cost with you if you have a way for me to contribute to your developing efforts 😄

Thank You for the kind offer. But I can afford a Graphics LCD Panel. I just don't want one!

Is the LCD Panel active during the G26 and locks up at completion of the G26? Can you help me establish a window of time where it goes sour?

I've noticed that when doing a G29 W before and after disconnecting, my z-offset appears to be lost during the disconnect.

I'll see what I can find on this.

@kmbecker13
Copy link

kmbecker13 commented Sep 28, 2016

I still see the X and Y values changing throughout the G26 process, and i can still kill the procedure by depressing the encoder wheel, but the temperatures don't seem to fluctuate much - which is odd. At the end of the print, the screen stops reflecting the current machine state altogether, both position and temperature.

After the G26 - If i command the head to move from a terminal, it moves, but the LCD will not update. The LCD also doesn't change if i send a G29 P4 or any other command until disconnecting. The encoder wheel on the LCD also doesn't seem to have any effect, not just the display itself. What i mean is that if i send a G29 Z, spinning the wheel doesn't drive the machine at all, so it's not just a visual problem

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 28, 2016

And right up to the end of the G26, can you press and hold the encoder wheel to terminate the G26 ?

What I'm wondering is this: The UBL system grabs control of the LCD Panel on certain events. The G26 is one of those events. I'm wondering if it isn't being given back to the system correctly. Or maybe it is in the 20x4 LCD case, but not the Graphics case?

@kmbecker13
Copy link

And right up to the end of the G26, can you press and hold the encoder wheel to terminate the G26 ?

For the most part, yes. I'm still seeing some weird behavior where i can't terminate the G26 at certain bed positions (seems to be on the x_max side) and i'm fairly certain it's not just poor button pressing on my part. I can do some testing later to confirm i can cancel late in the G26.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 28, 2016

I can do some testing later to confirm i can cancel late in the G26.

Please do! But the thing is, the G26 is really just a big loop. If you can cancel after one or two circles are drawn, that isn't any different than a cancel at the very end of circle drawing.

One more question, when you cancel in the middle of a G26 it tends to be OK? Is that correct? Is it when you finish all by itself that the LCD Locks up? Because that would be a valuable clue. In that case it would be going through different code paths.

@kmbecker13
Copy link

So i've been trying to knock out one print today and am seeing some weird behavior while printing a raft. The printer will get about an hour in and then either stops extruding randomly, drifts off the print surface and crashes or stops altogether - very weird.

In the most recent case, i noticed the following on my print control readout in S3D:

busy: paused for user
READ: echo:busy: paused for user

The LCD read M105 and after pressing the encoder, it resumed printing for another few minutes until it happened again and then just started going haywire in general (driving to random spots, slowly). I am also seeing this periodically in my print control readout:

WARNING: Firmware unresponsive. Attempting to force continue...
SENT: M105
READ: echo:busy: processing

I've never seen this before, so i'm fairly certain its in the firmware and not slicing or my printer itself.

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 29, 2016

Can you try the same print but do it from an SD Memory card? It would be
helpful to rule out a Serial Communication problem. But if you need to
hurry up and knock out a print, it might be best to load a more proven and
tested version of the Firmware.

@kmbecker13
Copy link

SD card print was successful! Sounds like it was a serial comms problem. Any idea what could be causing that?

@Roxy-3D
Copy link
Member Author

Roxy-3D commented Sep 30, 2016

SD card print was successful! Sounds like it was a serial comms problem. Any idea what could be causing that?

Well... it could be a lot of things. I've had trouble with lower quality USB cables causing the serial communications to lock up. And I've also had trouble with prints getting ruined when my machine running PronterFace decides it needs to run Micro$oft's Security Essentials to scan the disk for maleware. It seems the USB Serial Communications is not very robust. For sure the USB protocol is solid. It kind of feels to me like the AVR USB Serial stuff is a little bit problem prone. I don't know that that is true. But a lot of people are emphatic that you should never use the serial port for an important print. (And this isn't a Marlin issue. It is an AVR issue.)

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked and limited conversation to collaborators Mar 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants