- Dynamically readjusting your z height, bed mesh and tram the bed to make sure your first layer and every layer after that are perfect!
- The need to dynamically readjust z height is caused by the change in temperature of your frame
- Bimetallic frame components (Aluminum extrusion with steel linear rail) have different thermal expansion values
- This will make the bimetallic part deform as temperature raise up
- Improve overall print time by eliminating the need to do a bed mesh before each print
- Improve overall print time by enabling you to start the print without heat soaking
- This project lies upon the hard work and dedication of Deutherius, alchemyEngine and tanaes
- Although not involved in this specific project, most of the heavy lifting was done by them and most of the code in this project was writen by them.
- If there is someone I didn't credit it is only by mistake, please let me know!
If you suffer from any of the following:
- You've tried Virtual Gantry Backers and / or z_thermal_adjust and it made an improvement but didn't fully fix your problem
- Nicely laid first layer, but second layer is too high / too low and looks like crap
- Z offset changes between prints (too high / too low when the printer is heat soaked, but too low when it is not, or vice versa)
- Bed mesh doesn't seem to work well on full plates
- Have to heat soak the printer for hours just for the above problems to disappear
- Run the measure script without committing to anything, see what you get, it's free
- If you do have some changes in your bed mesh that require doing a bed mesh before each print, you can eliminate it all together with FDC and start your print faster
-
I consider VGB measure_thermal_behavior Klipper's z_thermal_adjust to be v1.0
-
1.0 works well for a lot of people, but it's because the diff between the needed value and the generated linear value is pretty close.
-
For printers that are bigger / hotter / weaker or just unlucky, linear compensation is not enough.
-
As I learned while trying to fix my top layers, frame deformation isn't linear, and it's printer specific.
-
Furthermore, the need to measure the changes to the mesh and the changes to the z height where double the time it needs to be
-
Hence - FDC:
- Improved measure script
- Improved generate thermal data scripts
- Dynamic and non-linear VGB (up to one mesh per 0.1C!)
- Dynamic and non-linear z height adjust using Klipper's z_thermal_adjust module
- Dynamic and Non-linear tramming
-
The picture shows the Z height changes per temperature, in the middle of the bed
- Dynamic un-tilt
- Smooth generated data to seamlessly change z heights and bed meshes
- Filter noise in generated data for even smoother operation (experimental)
- Will try to combat 1-5 microns changes that create small waves on flat layers
- Yes.
- Only applicable for auto tramming Z TILT at the moment
- QGL can be supported - see details below
- But the bed mesh should take care of it!
- Here why it doesn't -
- When you start the measuring phase - measuring the deformation, the script automatically tram the bed (QGL / Z TILT) once at the beginning of the test (let's say at 25.1C)
- All the bed meshes captured are relative to the current tramming
- You inserted the results into the macro and off you go to happily start a print
- But when you start a print, you tram the bed again before your start, now at a different temperature (Let's say 35.6C)
- This new tramming (QGL / Z TILT) values will probably be different from the one you captured all the bed meshes in your measurement phase
- Now all the bed meshes FDC is going to dynamically apply are relative to the tramming of a 25.1C frame
- They are invalid, and will not affectively compensate the current deformation
- Here why it doesn't -
- There are two scenarios where we won't need dynamic tramming:
- If you can guarantee that the tramming of your bed won't change ever and is identical to the one used in the measurement script (Which is unrealistic)
- i.e. You don't tram the bed before each print - Manual tramming with screws or something else
- You disable auto tramming (QGL / Z TILT)
- You ran the script with TRAM_EVERYTIME = True and the graphs of your z steppers were pretty close
- So, if your output graphs looks like this:
- Sorry buddy, You gonna need dynamic tramming
- Support z tilt
- quad_gantry_level is not supported at the moment because I don't have a quad printer
- I don't see any big obstacle implementing support for it, but it does require a different implantation then z tilt
- If anyone with a quad that ran TRAM_EVERYTIME = True and saw a need for it
- And also want to help - contact me, so I can maybe try and figure out the impalement together
- Another option is to hook me up with a quad printer
- The way it is implanted is by dynamically un-tilting the bed mesh itself using the modified bed_mesh.py klipper extra
- It's super cool, and I invested too many hours on it
- A new command that un-tilt and call z_thermal_adjust
- BED_MESH_PROFILE TILT_AND_LOAD={current_temp} CURRENT_TEMP={current_temp} REF_TEMP={ref_temp} stepper_z2=VAL2mm stepper_z=VAL0mm stepper_z1=VAL1mm
- You can actually see the modified bed mesh in the heightmap mainsail page (without the metadata)
- So bed mesh does take care of it?!?! well yes, now it does :)
- Measure changes in bed mesh, z height and bed tramming for x time
- Generate a cool graph that will show you the frame non-linear behavior
- Generate a non-linear series of bed meshes and z height changes with linear changes in between data points
- Interpolate them and filter noises to create a smooth graph
- Dynamically adjust z height using the current z_thermal_adjust module to create a non-linear change
- Dynamically switches bed meshes with the corresponding z height per temperature min, max and step
- Dynamically tram your bed - control each z stepper motor independently and apply in real time tilt / QGL corrections(not yet) to keep the bed plane parallel to the gantry plane, the amount of adjustments is made according to the data that was captured in the measurement phase
- Currently, only works in between the captured temps!
- So make sure the start really cold and time the test to finish with the hottest frame possible
- If you start the print with a lower temp then temp_min (or above temp_max) it will never change the z height
- If the frame temp goes above temp_max it will stop adjusting (but keep current adjustment)
- See roadmap
- When I developed this solution, I modified my printer to make the deformation more prominent, or should I say - extreme
- This enabled me to see exactly which solutions worked and which didn't
- And if it worked in this extreme case,and be so precise with just a few microns, it will surly work everywhere
- And work it did! it has been working flawless for some time now without hiccups
- It's not just great first layers, it's making sure every layer is beautifully buttery lushes and silky smooth
- Having said all that, you should know that there is a lot of guesstimations going on, and it can only be so accurate
- There might be some "waves" on your flat layers, that's just the nature of the ever-changing frame and the script fighting it
- Most of the time it will be smooth without any waves
- When the waves accrue they should be minimal - 2-5 microns
- If it's more than that and your layers become rough - too low / too high
- Contact me please
It WILL work for "linear deformed frames", so it's not about choosing between VBG and FDC, FDC is an improved version
- Research different bed temps to see if there is a difference in the way things scale
- Implement multi bed temp support if needed
- Generate non-linear equation to produce more points below and above captured temps
- (Done)
Save results to disk for every new mesh(Will now saves data if there is a keyboard interrupt or a runtime exception)Currently, only saves at the end
Check out the following repositories:
Gantry bowing-induced Z-offset correction through relative reference index, to fix that inconsistent Z offset between heatsoaked and not-as-well heatsoaked printer (pairs nicely with virtual gantry backers, but do this one first)
Virtual Gantry Backers, a dynamic mesh loading system that counteracts gantry bowing due to bimetallic thermal expansion of gantry members
measure_thermal_behavior, This script runs a series of defined homing and probing routines designed to characterize how the perceived Z height of the printer changes as the printer frame heats up. It does this by interfacing with the Moonraker API, so you will need to ensure you have Moonraker running.
- If you suffer from X bowing (you can see a bowed bed mesh)
- While hot, try loosening the screws that hold the linear rail, just a bit, to allow for some movement when expending
- Do a before and after bed mesh and see if there is any difference
- Same goes for Y
- You gonna need to run the measure script again if you change anything
- The most important thing to know is that we need a point in the mesh to be in the center of the bed
- Without it the script won't work!
- Example: for 400 bed and 9,9 mesh point number 41 should be the middle of the bed (200x200)
- Make sure that when you home Z, the PROBE (not nozzle) is at the center of the bed
- Sometimes the Z home doesn't take into account the probe location!
- You will have to fix it before you can continue
- If you are using RatOS, it's currently a known issue, here is the fix
- Improve the speed of your probing and disable fade - long probe sequences will capture a distorted bed mesh due to the fast warming up of the bed and frame
- For our purposes, a quick probe is usually sufficient. Below are some suggested settings:
- Keep in mind - There is a real problem in the start of the test where the frame temps rise up really fast, that causes the mesh we captured to be distorted if the mesh takes too long
[probe]
...
speed: 10.0
lift_speed: 15.0
samples: 1
samples_result: median
sample_retract_dist: 1.5
samples_tolerance: 0.02
samples_tolerance_retries: 1
- Mesh min/max - find out the maximum you can probe with your current probe.
- your mesh min max should have the same offset.
- if you can reach x max of 280, then mesh min should be 20, if 250 then min is 50
- your mesh min max should have the same offset.
- probe_count - Have to be an odd number so will be left with a center point!
- (5, 5) / (7,7) / (9,9) are good options
- fade - DISABLED!
- horizontal_move_z - as low as possible without wreaking havoc
- z_positions - our modified version of bed_mesh.py requires it.
- You only need it if you gonna use the TRAM_EVERYTIME = True feature
- It's the same as in z_tilt
[bed_mesh]
#######fast settings
speed: 500
horizontal_move_z: 5 # Should be more than your z_offset otherwise you will crash your nozzle!
fade_end: 0
mesh_min: 40,40
mesh_max:260,260
probe_count: 7,7
- When everything is set up correctly, you should have a 0.0 point in the middle of the array after a bed mesh
- Maybe not 0.0 but close to it
- Enable z_thermal_adjust in your config with temp_coeff=0
- This is where you define your frame sensor
- Remove VBG if you have it
- X gantry on the opposite side of the X endstop at the end, touching the aluminum
- I know, it's a pain to find a way to install it, but it's the only place to put the sensor that will give accurate results
- Other places are a gamble, try it if you want - if it works, great, if it doesn't, you know why
- I used a cheap ATC Semitec 104GT-2 104NT-4-R025H42G Thermistor Cartridge
- You can use whatever you want as long as it touches the aluminum (and not the rail!)
- Make sure to cover i. so it will be isolated from the air
- I put it on my umbilical, with drag chains it might be easier
- They way I did it is by sacrificing the last screw on my linear rail, push the thermistor to it and then shoved a piece of foam between the thermistor and the rail to have consistent good contact with the aluminum
- Python 3.7 required (3.7 has ordered dicts by default)
- Edit measure_thermal_behavior.py and change the required parameters.
- It is recommended that the bed temp will be your working bed temp, if you print ABS and PETG and require different bed temps there is a chance that the meshes will be different. A more robust version that support multiple bed temps will be made in the future
- You want to let it run as much as possible until the printer frame temperature reaches the highest temp you've seen during a long print
- Currently, the script will not generate bed meshes and z heights above and below the captured temperatures due to its non-linear behavior
- HOT_DURATION - Recommended is 3 hours, you wanna catch them all (temperature data points)
- The bed and hotend temperature should be the exect one you print your first layer with
- If you print ABS and PETG, you currently need to do the test separately for each bed and hotend temperature
- TRAM_EVERYTIME = True - Only z_tilt printers are supported at the moment
- You want to set it to False if your printer is not supported
- And you want to then wait a day and run it again with True to see what your tilt situation is
- Make sure the frame is at the lowest temperature possible (like after it was idle for a night)
- If you have any fans / nevermore, start them after the first mesh is done
- Simulate the same wind you going to have in the enclosure during a print
- But give it a chance to capture the initial bed mesh
- NOTE: your X bowing is directly affected by the temperature of your X gantry
- So If you have a really long probe for example, the gantry will be higher from the bed then it would if it's printing the first layer, this 5mm-20mm will greatly affect the temperature of the gantry and the bowing.
- Part cooling fan cool the X gantry a bit, which will also reduce the bowing, and for the first layer there is no fan so take that into account (don't run the cooling fan during the test)
git clone https://github.com/JiMcNulty/FDC
cd FDC
vim measure_thermal_behavior.py
nohup python3 measure_thermal_behavior.py 0.1 > out.txt &
tail -F out.txt
- temperature_step = the step accuracy in degree Celsius, default to 0.1
- restart without saving the config to remove all the bed meshes, they are there to save the progress as a recovery option, you don't need them if you got a full json file
- If you saved the config that's alright, you can manually delete the meshes later
- Take the output json file and run generate_FDC_meshes_z_heights.py json_file temperature_step --filter_noise / --no-filter_noise
- Run it on your local PC
- noise filter - Enable filtering noise for a smoother graph. if the generated graphs don't look right, disable it (default: True)
python3 -m pip install -r requirements.txt
python3 generate_FDC_meshes_z_heights.py json_file 0.1 --filter_noise
- While running, you will be shown some generated graphs and the smooth version of them
- It is shown to you so you can examine it
- If they don't look right to you i.e. the filtering and smoothing made it look like it doesn't follow the points - don't use the data
- Disable filtering and try again
- Edit the FDC.cfg macro file - copy the output results from the cmd console
- Edit the macro with the min max temp, step and z_height_temps dictionary that was printed when you ran the script
- variable_precision is the precision of step. ie - 0.1 step is 1, 0.05 is 2, 1 is 0
- Copy the generated mesh from the new cfg file and paste it at the bottom of your printer.cfg
- Paste if after the string ...-- SAVE_CONFIG --...
- And after the default bed mesh
- If you don't have one just copy your first bed mesh and change the name
- This two things are mandatory for klipper
- Copy the macro FDC.cfg to the same folder as printer.cfg
- Add [include FDC.cfg] to your printer.cfg
- Only if applicable (if you set TRAM_EVERYTIME to True) you will need to override the bed_mesh.py file
1. /home/pi/klipper/klippy/extras/
2. replace bed_mesh.py
3. delete bed_mesh.pyc
4. add this to your config
[bed_mesh]
...
# For TRAM_EVERYTIME = True add this:
# values should match your machine, this is just an example
z_positions:
0,0
150,300
300,0
- Save
- Shutdown and start (to ensure the bed_mesh.py will load)
- Don't forget to check that it's still there after you do a Klipper update
- If you did a bed mesh every start print you can disable it, you won't need it anymore
- Reset and redo your z_offset!!!
- Fail to do so will risk crashing the nozzle!!
- Take note of your min and max temp, if you start a print when your frame temp is below or above it, the script won't run
- You will see a repeating error during printing
- Bed meshes will be switched dynamically and seamless
- z_themral_adjust will be adjusted in real time
- Turning it from a linear module to non-linear
- ref_temp is part of the z_thermal Klipper module
- It is set every time you home Z (like before you start a print when you home all axis)
- The error "out of range" is a FDC error
- The print has started before the gantry temp is in the captured range (variable_temp_min) so FDC won't start working
- To fix it, just heat the printer a little before you start, 1-2 min
- If you didn't start the measure test when the printer was cold then you might want to re-do the measurement.
You can dm me on discord if you have any issues, i'm on the Voron and Ratrig servers I don't want to put the user name here to avoid bot spamming, but search for the github link, and you'll find me (t.c)
- I'm really interested in what your deformation looks like ;)
- Really, i'm curious to see the graphs and all other data you've collected about the printer
- There might be other things that I will see that can improve the script!