Klipper3d / klipper

Klipper is a 3d-printer firmware
GNU General Public License v3.0
8.99k stars 5.17k forks source link

bed_mesh: Implement adaptive bed mesh #6461

Closed voidtrance closed 5 months ago

voidtrance commented 5 months ago

This PR is for an implementation of adaptive bed meshes. Adaptive bed meshes use the exclude objects data to determine the area of the print bed being used and only create a mesh for that bed area. This has the benefit of greatly decreasing the amount of time needed to start a print without compromising print quality.

These changes have been tested on both Cartesian and Delta printers through the use of SimulAVR (with some custom Klipper modifications to enable it to report probe point z offset through Moonraker) and by many actual users in the Voron Discord.

Below is a ZIP archive containing two HTML files that show the behavior of the adaptive mesh. Plots where generated using test data from the SimulAVR simulation.

adaptive-mesh-plots.zip

The commands issues to define the print objects that produce these plots are below:

commands-cartesian.txt commands-delta.txt

kyleisah commented 5 months ago

Amazing! Thank you for all your impressive work on this! 😄

Arksine commented 5 months ago

The latest changes look good. One minor thing I missed earlier is that we should add the adaptive_margin option to the Config Reference as well. When that is done I'm ready to approve the PR.

voidtrance commented 5 months ago

The latest changes look good. One minor thing I missed earlier is that we should add the adaptive_margin option to the Config Reference as well. When that is done I'm ready to approve the PR.

Done.

I also re-ran the simulated tests with the latest revision and compared it against the graphs that were generated with the original version submitted with the PR to make sure that thing did not break during the review edits.

KevinOConnor commented 5 months ago

Thanks. Happy to commit. I think we should give a few days to see if there are any other comments. Assuming nothing else comes up, I'll look to commit next week.

-Kevin

kyleisah commented 5 months ago

Thanks. Happy to commit. I think we should give a few days to see if there are any other comments. Assuming nothing else comes up, I'll look to commit next week.

Amazing, thank you so much!

marbocub commented 5 months ago

Hello, I'm interested in this PR. When the purge line in a start gcode is not labeled and is too far from printing objects, the nozzle may scratch the table at the line in the worst case because it is not probed around the line.

I think this has to be careful and think it would be helpful to include a note or a labeling method in the document.

voidtrance commented 5 months ago

Hello, I'm interested in this PR.

When the purge line in a start gcode is not labeled and is too far from printing objects, the nozzle may scratch the table at the line in the worst case because it is not probed around the line.

I think this has to be careful and think it would be helpful to include a note or a labeling method in the document.

I am not sure that I understand. Are you asking for the purge line area to be probed or to document that the purge line area is not probed?

Whether the purge line will be probed depends entirely on the slicer-generated gcode. If the slicer generates a purge line that is labeled as an object, it will be probed. Otherwise, it won't.

I think that describing all of that and documenting slicer behavior is beyond the scope of Klipper documentation.

marbocub commented 5 months ago

or to document that the purge line area is not probed?

Yes, this is my opinion.

Whether the purge line will be probed depends entirely on the slicer-generated gcode. If the slicer generates a purge line that is labeled as an object, it will be probed. Otherwise, it won't.

I think it would be kind to include this content or simply the first half to the document. This may reduce a user accidentally scratching the table.

kyleisah commented 5 months ago

I think it would be kind to include this content or simply the first half to the document. This may reduce a user accidentally scratching the table.

There is the adaptive_margin configuration to expand the bounds of the mesh, so purging may not be necessary as you can “purge” using something like a skirt.

Speaking from experience here, I’ve ran many, many adaptive meshes and have used many different purge configurations (adaptive and static) and have not damaged a buildplate or nozzle.

I believe it should be left up to the user what they feel is best to handle that, however I do not foresee it being a problem.

marbocub commented 5 months ago

I understand. I appreciate your consideration for all.

kyleisah commented 5 months ago

I understand. I appreciate your consideration for all.

I appreciate you understanding. I do, however, agree that although I've had no problems with it in the past, if someone's machine is a unique setup or has mechanical issues causing them to rely on a full mesh, that should be laid out clearly. It would require a fairly unique complication with the machine, but I suppose it is possible afterall that issuing print moves outside of the adaptive meshing area can be problematic.

Sineos commented 5 months ago

if someone's machine is a unique setup

@marbocub's concern is essentially valid. In the support activities, I have seen enough bed topologies that range from -0.5 to +0.5 or even worse. It seems that many users mistake bed-meshing as an alternative to leveled bed or generally have completely crooked beds.

Maybe a sound recommendation would be building a mesh of the entire bed and review it. If it deviates more than 1 layer-height, adaptive meshing should be used with caution.

Sineos commented 5 months ago

In addition: Not sure if the adaptive meshing changes anything here, but usually the "boundary" points of a mesh are carried over to the unmeshed region. This might even create another challenge for crooked beds. Let's assume your last meshed point was -0.2 but for whatever reason your bed starts rising to +0.5 outside this point. Now, carrying over -0.2 to the "physical +0.5 region" increases your problem to 0.7.

kyleisah commented 5 months ago

Maybe a sound recommendation would be building a mesh of the entire bed and review it. If it deviates more than 1 layer-height, adaptive meshing should be used with caution.

Yeah, I fully agree here. I will adjust the suggestion I've made with some more verbiage about this. I can fully relate with seeing some... "interesting" mesh results, so the concern is totally valid.

In addition: Not sure if the adaptive meshing changes anything here, but usually the "boundary" points of a mesh are carried over to the unmeshed region.

This is correct, I actually just double-checked this was the behavior today because I was not sure how that is handled. But yes. You can imagine it sort or like a bowl with a very wide flange. The edges of the mesh are scaled out in XY to infinity.

Some of these cases we are imagining are very extreme, almost as if generating a bed mesh on a waffle-iron, but they are absolutely within the realm of possibility.

Arksine commented 5 months ago

New changes look good to me. Thanks.

marbocub commented 5 months ago

New changes resolved the concern I had. Thank you very much.

kyleisah commented 5 months ago

New changes resolved the concern I had. Thank you very much.

Wonderful! Thank you for bringing those concerns forward. It’s best to correctly set the expectation in the documentation rather than leave it up for interpretation. 😄

KevinOConnor commented 5 months ago

Thanks!

I committed this change. I also added my signed-off-by just to acknowledge the change to the copyright statement .

-Kevin

Grex3D commented 5 months ago

Hi guys, after using adaptive bed mesh, i don't understand how to load it (to see it in heighmap) ? thanks :)

kyleisah commented 5 months ago

@KevinOConnor @Arksine @voidtrance we might have a problem here. I just tried this as well and there's no heightmap showing up in my web interface (mainsail). However, when I use BED_MESH_OUTPUT I do see mesh information there, I just can't see it in the frontend anymore. This might be related to the small bit of code that was changed to help prevent people from saving adaptive meshes and re-using them, so this might actually be a problem that mainsail/fluidd or other frontends might have to patch. I'm not sure, just wanted to report my findings here.

kyleisah commented 5 months ago

@meteyou perhaps this is something you should be aware of. Seems adaptive meshes do not show up in the heightmap GUI as they are only meant to be used during prints. If the machine status is "printing" or “paused” the mesh information is being used, and when the print has finished or is cancelled I believe the mesh information will be removed.

voidtrance commented 5 months ago

How do the front ends get the mesh data (coordinates and height)?

kyleisah commented 5 months ago

Thankfully it’s not a pressing issue or problem, as the mesh information is in fact being used during a print, we just don’t have a visual representation in the frontend currently.

hex-344505 commented 5 months ago

Hi, not sure if it is right place. How to enable this feature? my config section looks like

[bed_mesh]
speed: 500
horizontal_move_z: 5
#horizontal_move_z: 10
mesh_min: 30, 30
mesh_max: 320, 320
probe_count: 7,7
adaptive_margin: 5
mesh_pps: 2,2
algorithm: bicubic
bicubic_tension: 0.2
move_check_distance: 3
split_delta_z: 0.01
fade_start: 2.0 
fade_end: 10.0
fade_target: 0

But printer probed all the bed. Previously used KAMP to make adaptive bed. Thought it should be enabled by default and did not find documented way to enable it.

voidtrance commented 5 months ago

Hi, not sure if it is right place. How to enable this feature?

my config section looks like


[bed_mesh]

speed: 500

horizontal_move_z: 5

#horizontal_move_z: 10

mesh_min: 30, 30

mesh_max: 320, 320

probe_count: 7,7

adaptive_margin: 5

mesh_pps: 2,2

algorithm: bicubic

bicubic_tension: 0.2

move_check_distance: 3

split_delta_z: 0.01

fade_start: 2.0 

fade_end: 10.0

fade_target: 0

But printer probed all the bed. Previously used KAMP to make adaptive bed. Thought it should be enabled by default and did not find documented way to enable it.

The documentation has not made it to the website yet.

You add the ADAPTIVE=1 to the BED_MESH_CALIBRATE command.

Arksine commented 5 months ago

How do the front ends get the mesh data (coordinates and height)?

Its reported by the BedMesh.get_status() method. My guess is that Mainsail is getting confused by an empty string value in the profile_name field, because the mesh data itself does reflect the current adaptive mesh. It appears that Fluidd doesn't validate the current profile name and therefore renders the heightmap.

Since we introduced a minor change in behavior with profile reporting I think the burden is on us to correct it. I'm working on a patch now. I already had some other minor work that needed to be done, so I will add it in the same PR.

voidtrance commented 5 months ago

How do the front ends get the mesh data (coordinates and height)?

Its reported by the BedMesh.get_status() method. My guess is that Mainsail is getting confused by an empty string value in the profile_name field, because the mesh data itself does reflect the current adaptive mesh. It appears that Fluidd doesn't validate the current profile name and therefore renders the heightmap.

Since we introduced a minor change in behavior with profile reporting I think the burden is on us to correct it. I'm working on a patch now. I already had some other minor work that needed to be done, so I will add it in the same PR.

Thank you. I was planning on trying to figure it out but Mainsail code is completely new to me plus I wouldn't have had time until Monday.

I appreciate you jumping in with the fix.

zellneralex commented 5 months ago

As a short note, yes the empty string is the issue, @meteyou is already working on it. ‘He deceive to refactor the module so the fix should be part of the next Mainsail release

@pedrolamas: you need to check that for Fluidd also

matmen commented 5 months ago

Fluidd correctly shows the adaptive mesh, it just doesn't show up in the profile list (as expected): image

zellneralex commented 5 months ago

@matmen I do not doubt that, we saw the same as long a mesh like default was loaded before the execution with ADAPTIVE=1. Your picture shows also the name default.

So you should test if again if fluidd does not name a mesh with an empty name string default.

@voidtrance can you check that the name will also be an empty string if a mesh was already loaded, currently it looks like the name stays whatever it was before. Here is a picture of the data when you load a default mesh at Klipper init. E.g. using a delayed_gcode image

and here the same print with no mesh loaded before image

matmen commented 5 months ago

@zellneralex The default bed mesh shows up because it's defined in my config - fluidd just shows the reported mesh list, which doesn't include the adaptive mesh (with an empty name). We only use the bed mesh name for showing which mesh profile is active, which is why the "default" profile in the screenshot is showing a load button.

If there's no bed mesh profiles reported, we just show a message, but the visualization still shows up: image

zellneralex commented 5 months ago

@zellneralex The default bed mesh shows up because it's defined in my config - fluidd just shows the reported mesh list, which doesn't include the adaptive mesh (with an empty name). We only use the bed mesh name for showing which mesh profile is active, which is why the "default" profile in the screenshot is showing a load button.

If there's no bed mesh profiles reported, we just show a message, but the visualization still shows up: image

Perfect, then fluidd should be save.

Arksine commented 5 months ago

FWIW, #6473 will add profile names to the adaptive mesh. It will be something like adaptive-<hexstring>, where the hexstring is the mesh's internal object id. That will make it relatively unique. It isn't intended that users save these meshes, although they could if they wanted to (perhaps for some experiment).

kyleisah commented 5 months ago

Really appreciate the rapid and collaborative work to patch this you guys. 😄 Thanks for doing that.

I've been monitoring some discord servers and forums and it seems like there are some areas the documentation is still lacking. I'll fork klipper and make some changes to the docs to improve any gaps in configuration/setup and make a PR. Really it just boils down to setting up exclude_object correctly and some other small things. Thank you again!

AudreyAP commented 5 months ago

@Arksine Is it maybe a good idea to add an option to make save_config ignore adaptive-xxxx meshes?

voidtrance commented 5 months ago

@Arksine Is it maybe a good idea to add an option to make save_config ignore adaptive-xxxx meshes?

Arksine already mentioned in his fix up commit message that he is explicitly allowing the saving of adaptive meshes in case anyone wants to use them for some type of testing/research.

Arksine commented 5 months ago

You have to explicitly call BED_MESH_PROFILE SAVE=xxxx after probing an adaptive mesh to save it. You could call it adaptive-xxx or anything else. Without this step SAVE_CONFIG will ignore it.

AudreyAP commented 5 months ago

🤦‍♀️ whoops, I totally missed that.

Sounds great, thank you both.

kot0005 commented 5 months ago

Hi this feature is not working. I am on mainsail. It still probes the whole bed.

I was using a different adaptive bed mesh and it was working.

image

image

image

I dont save my meshes because i have a belted z and the bed needs to be calibrated every time as the bed drops a bit after steppers are disabled.

AudreyAP commented 5 months ago

@kot0005 remove the bed_mesh_profile load=default line, and send a screenshot of your start gcode settings in slicer.

kot0005 commented 5 months ago

@kot0005 remove the bed_mesh_profile load=default line, and send a screenshot of your start gcode settings in slicer.

hi, this is my start g code in slicer START_PRINT BED_TEMP=[first_layer_bed_temperature] EXTRUDER_TEMP=[first_layer_temperature]

if i remove the line you mentioned, will it still use the mesh it calibrated from the calibrate command ?

ty

AudreyAP commented 5 months ago

@kot0005 if you leave the line in there, it most definitely won't work.

Try adding M117 before you call start_print in slicer start gcode.

kot0005 commented 5 months ago

@kot0005 if you leave the line in there, it most definitely won't work.

Try adding M117 before you call start_print in slicer start gcode.

i removed the load profile code, no change. will try m117 image

kot0005 commented 5 months ago

@kot0005 if you leave the line in there, it most definitely won't work.

Try adding M117 before you call start_print in slicer start gcode.

mate the M117 in the slicer makes my printer start printing the file without heating anything..

ty for the help but i have gone back to my original gcode base adaptive mesh and working perfectly. This is def not ready for plug and play.

AudreyAP commented 5 months ago

@kot0005 if adding M117 before print start makes your print start not work, your config is severely broken. Swing by the discord server and we can get it working, don't want to continue spamming this pr. The feature works exactly as expected, this is a config issue.

kot0005 commented 5 months ago

@kot0005 if you leave the line in there, it most definitely won't work. Try adding M117 before you call start_print in slicer start gcode.

mate the M117 in the slicer makes my printer start printing the file without heating anything..

Isnt the whole point of PRINT_START is to use the Gcode macros set up in the config file ? adding M117 Ignores all of this, not to mention it could damage the hotend extruder if its starts to print without heating up. Luckily mine was already heated a bit from previous test print.

I opened a topic on discord with my config file now. I dont think there is anything wrong with it.

AudreyAP commented 5 months ago

@kot0005 m117 simply clears the display. It absolutely does not stop print_start from working. I assume that you have misread and have replaced print_start with m117, which is not what I suggested.

kot0005 commented 4 months ago

@kot0005 m117 simply clears the display. It absolutely does not stop print_start from working. I assume that you have misread and have replaced print_start with m117, which is not what I suggested.

i did not replace print start.. i added M117 before print start like you suggested.

zellneralex commented 4 months ago

What we really need is a sliced gcode file, we have seen that the exclude object definition was placed below the first user defined gcode. As said the feature works as intended, for setup help and debugging of your system use the Klipper discord.

voidtrance commented 4 months ago

@kot0005 m117 simply clears the display. It absolutely does not stop print_start from working. I assume that you have misread and have replaced print_start with m117, which is not what I suggested.

i did not replace print start.. i added M117 before print start like you suggested.

@kot0005 Please, let's not use the PR thread for debugging issues. There are other forums better suited for this.

What we really need is a sliced gcode file, we have seen that the exclude object definition was placed below the first user defined gcode. As said the feature works as intended, for setup help and debugging of your system use the Klipper discord.

For what it's worth, a PR was merged a couple of days ago to the preprocessing script that fixes this and the M117 hack is no longer needed. I don't know how long it will take for it to make it's way into Moonraker's environment, however.