Jason does this work on both UI versions? I would love to try and automate some of the calibration stuff.
Poking around at all your updates, tests, extensions, and all the other magic you keep pulling out of your hat. I want it all but I think your theming and this leveling are highest on the list.
I changed all the settings I needed, first left probe goes fine. Instead of going to Z10 at the specified federate it goes to Z max superfast, ignores my Z endstops and starts probing again. At this point it smashed my endstops out of the way (luckily they were kinda loose). The second z probe actually read very similar so I assume it did not actually Z home and reset or anything. It just went up my max probe distance and started again.
This is a bit of a magic number that I’m not 100% confident in. It’s trying to find the pivot points of the beam. Center of Z stepper to center of Z stepper sounds about right for LR4. I think it’s a bit more obvious with the LR4 design. With the LR3, the YZ plate being offset from the Y rail complicates it in my head.
I just ran this quick on v3 (which shouldn’t matter) and something is off. It did the 3 left probes ok, but then the home Z ignored the endstops and skipped steps. Then when it went right, it went too far. In the end it did update the Z pulloffs with reasonable looking values.
I hadn’t tried this since 3.8.3 so let me check it out a bit closer against 3.9.1 in the next day or two.
Not sure about the feedrate but this updated version at least works ok again. I made some rookie mistakes. I updated it to initialize to G21 G90 G94 and zero with G92. I think not having some of that made for a questionable starting state. Also, moving to positive Z values is questionable since I wasn’t zeroing on the surface. It was probably probing around -80 and then trying to go to positive 10. Oops. So, I changed the Z moves to relative with G91. That fixes the crashing into the Z endstops. For my crash in X max, that was because since I last did this, I increased my X pulloffs because they aren’t reliable if you go too small (I think they were at 2 now at 4). Those extra 2mm got me.
Z Leveling Gcode
(PRINT, LowRider Z Leveling for FluidNC v3.9.1 or higher)
(UPDATE REQUIRED)
#<probeYPos> = 50 (Y position to probe at dependent upon condition of spoilboard)
#<probeXLeftPos> = 0 (Left X position to probe at dependent upon condition of spoilboard)
#<probeXRightPos> = 870 (Right X position to probe at, should be close to max X)
#<xTotalDistance> = 1080 (Total X Distance - On LR3, this is from left bearing to Y rail)
#<zMotorLeft> = 0 (Left Z Motor - 0 if Z0 is on the left, 1 if Z1 is on the left)
(UPDATE OPTIONAL)
#<minPulloff> = 4.0 (Minimum pulloff value)
#<jogXYFeedrate> = 1000 (Feedrate for X and Y jogging)
#<jogZFeedrate> = 500 (Feedrate for Z jogging)
#<jogHeight> = 30 (Z height when jogging in X or Y)
#<probeDistance> = -80 (Max probe distance, should be negative)
#<probeFeedrate> = 200 (Feedrate when probing)
#<probeCount> = 3 (Number of times to probe on each side)
(PRINT, Home All and Initialize)
$H
G21
G90
G94
G92 X0 Y0 Z0
(PRINT, Move to Initial Y Position %d#<probeYPos>)
G00 Y#<probeYPos> F#<jogXYFeedrate>
(PRINT, Move to Initial X Position %d#<probeXLeftPos>)
G00 X#<probeXLeftPos> F#<jogXYFeedrate>
M0 (PRINT, Attach Probe and Probe Left x%d#<probeCount>)
#<probeSum> = 0
o100 repeat [#<probeCount>]
G38.2 Z#<probeDistance> F#<probeFeedrate>
#<probeSum> = [#<probeSum> + #5063]
G00 G91 Z10 F#<jogZFeedrate>
(PRINT, Probe Left Z: #5063)
o100 endrepeat
#<probeLeftAvg> = [#<probeSum>/3]
M0 (PRINT, Detach Probe Before Moving to Z%d#<jogHeight> and X%d#<probeXRightPos>)
G00 Z#<jogHeight> F#<jogZFeedrate>
G00 X#<probeXRightPos> F#<jogXYFeedrate>
M0 (PRINT, Re-attach Probe and Probe Right x%d#<probeCount>)
(MSG Probe Right)
#<probeSum> = 0
o101 repeat [#<probeCount>]
G38.2 Z#<probeDistance> F#<probeFeedrate>
#<probeSum> = [#<probeSum> + #5063]
G00 G91 Z10 F#<jogZFeedrate>
(PRINT, Probe Right Z: #5063)
o101 endrepeat
#<probeRightAvg> = [#<probeSum>/3]
(PRINT, Z Average: Left=#<probeLeftAvg>, Right=#<probeRightAvg>)
#<zDifference> = [ABS[ABS[#<probeLeftAvg>] - ABS[#<probeRightAvg>]]]
(PRINT, Z Difference: #<zDifference>)
#<xDistance> = [#<probeXRightPos> - #<probeXLeftPos>]
#<zOffsetChange> = [[#<zDifference> / #<xDistance>] * #<xTotalDistance>]
(Get current Z pulloff values)
#<z0Pulloff> = #</axes/z/motor0/pulloff_mm>
#<z1Pulloff> = #</axes/z/motor1/pulloff_mm>
(Calculate New Pulloff Values)
#<z0PulloffNew> = #<z0Pulloff>
#<z1PulloffNew> = #<z1Pulloff>
o102 if [[#<zMotorLeft> EQ 0] AND [#<probeLeftAvg> GT #<probeRightAvg>]]
#<z1PulloffNew> = [#<z1PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 1] AND [#<probeLeftAvg> GT #<probeRightAvg>]]
#<z0PulloffNew> = [#<z0PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 0] AND [#<probeRightAvg> GT #<probeLeftAvg>]]
#<z0PulloffNew> = [#<z0PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 1] AND [#<probeRightAvg> GT #<probeLeftAvg>]]
#<z1PulloffNew> = [#<z1PulloffNew> + #<zOffsetChange>]
o102 endif
(PRINT, New Pulloff Values Prior to Normalizing: Z0=#<z0PulloffNew>, Z1=#<z1PulloffNew>)
(Normalize New Pulloff Values to Minimum Pulloff)
#<change> = 0
o103 if [#<z0PulloffNew> LT #<z1PulloffNew>]
#<change> = [#<minPulloff> - #<z0PulloffNew>]
#<z0PulloffNew> = #<minPulloff>
#<z1PulloffNew> = [#<z1PulloffNew> + #<change>]
o103 elseif [#<z0PulloffNew> GT #<z1PulloffNew>]
#<change> = [#<minPulloff> - #<z1PulloffNew>]
#<z1PulloffNew> = #<minPulloff>
#<z0PulloffNew> = [#<z0PulloffNew> + #<change>]
o103 endif
(PRINT, Z0 Pulloff: Current=#<z0Pulloff>, New=#<z0PulloffNew>)
(PRINT, Z1 Pulloff: Current=#<z1Pulloff>, New=#<z1PulloffNew>)
M0 (PRINT, Continue to Update Pulloff Values)
(Set Pulloff Values)
#</axes/z/motor0/pulloff_mm> = #<z0PulloffNew>
#</axes/z/motor1/pulloff_mm> = #<z1PulloffNew>
(Save Pulloff Values to Config File)
$CD=config.yaml
(PRINT, Z Leveling Complete)
Instead of moving up 10, should it home each time? That seems like while it would take longer it would result in a more accurate average? That would average the trigger position and the probe position. Currently, it just averages the probe position?
I still can not believe something like this is possible in gcode. This ability seems like there is now a second reason not to be using Marlin.
Thank you so much for trying this, fixing it, showing us what is possible. When this is all tested and working great you really should share it on the fluid discord. I am sure they would love to see it, and others could learn a lot from it.
I just tried your new gcode and its not working right. Do you have it zeroing x and y after it moves to where you have it take the first probe?
I have it taking the first probe at X30 Y60 The second probe at X1250 Y60. When it moved to the second probe it went to X1280 which is 3 more mm of travel than I have lol.
So wait that’s not zeroing X and Y, but its moving relative instead of actual position.
Your G91 for the Z is also making the X move relative instead of actual. So should I set my second X position to a relative number to the first or will that throw off the calculations?
(PRINT, LowRider Z Leveling for FluidNC v3.9.1 or higher)
(UPDATE REQUIRED)
#<probeYPos> = 60 (Y position to probe at dependent upon condition of spoilboard)
#<probeXLeftPos> = 30 (Left X position to probe at dependent upon condition of spoilboard)
#<probeXRightPos> = 1250 (Right X position to probe at, should be close to max X)
#<xTotalDistance> = 1509 (Total X Distance - On LR3, this is from left bearing to Y rail)
#<zMotorLeft> = 0 (Left Z Motor - 0 if Z0 is on the left, 1 if Z1 is on the left)
(UPDATE OPTIONAL)
#<minPulloff> = 4.0 (Minimum pulloff value)
#<jogXYFeedrate> = 1000 (Feedrate for X and Y jogging)
#<jogZFeedrate> = 500 (Feedrate for Z jogging)
#<jogHeight> = 30 (Z height when jogging in X or Y)
#<probeDistance> = -100 (Max probe distance, should be negative)
#<probeFeedrate> = 100 (Feedrate when probing)
#<probeCount> = 3 (Number of times to probe on each side)
(PRINT, Home All and Initialize)
$H
G21
G90
G94
G92 X0 Y0 Z0
(PRINT, Move to Initial Y Position %d#<probeYPos>)
G00 Y#<probeYPos> F#<jogXYFeedrate>
(PRINT, Move to Initial X Position %d#<probeXLeftPos>)
G00 X#<probeXLeftPos> F#<jogXYFeedrate>
M0 (PRINT, Attach Probe and Probe Left x%d#<probeCount>)
#<probeSum> = 0
o100 repeat [#<probeCount>]
G38.2 Z#<probeDistance> F#<probeFeedrate>
#<probeSum> = [#<probeSum> + #5063]
G00 G91 Z10 F#<jogZFeedrate>
(PRINT, Probe Left Z: #5063)
o100 endrepeat
#<probeLeftAvg> = [#<probeSum>/3]
M0 (PRINT, Detach Probe Before Moving to Z%d#<jogHeight> and X%d#<probeXRightPos>)
G00 Z#<jogHeight> F#<jogZFeedrate>
G00 X#<probeXRightPos> F#<jogXYFeedrate>
M0 (PRINT, Re-attach Probe and Probe Right x%d#<probeCount>)
(MSG Probe Right)
#<probeSum> = 0
o101 repeat [#<probeCount>]
G38.2 Z#<probeDistance> F#<probeFeedrate>
#<probeSum> = [#<probeSum> + #5063]
G00 G91 Z10 F#<jogZFeedrate>
(PRINT, Probe Right Z: #5063)
o101 endrepeat
#<probeRightAvg> = [#<probeSum>/3]
(PRINT, Z Average: Left=#<probeLeftAvg>, Right=#<probeRightAvg>)
#<zDifference> = [ABS[ABS[#<probeLeftAvg>] - ABS[#<probeRightAvg>]]]
(PRINT, Z Difference: #<zDifference>)
#<xDistance> = [#<probeXRightPos> - #<probeXLeftPos>]
#<zOffsetChange> = [[#<zDifference> / #<xDistance>] * #<xTotalDistance>]
(Get current Z pulloff values)
#<z0Pulloff> = #</axes/z/motor0/pulloff_mm>
#<z1Pulloff> = #</axes/z/motor1/pulloff_mm>
(Calculate New Pulloff Values)
#<z0PulloffNew> = #<z0Pulloff>
#<z1PulloffNew> = #<z1Pulloff>
o102 if [[#<zMotorLeft> EQ 0] AND [#<probeLeftAvg> GT #<probeRightAvg>]]
#<z1PulloffNew> = [#<z1PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 1] AND [#<probeLeftAvg> GT #<probeRightAvg>]]
#<z0PulloffNew> = [#<z0PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 0] AND [#<probeRightAvg> GT #<probeLeftAvg>]]
#<z0PulloffNew> = [#<z0PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 1] AND [#<probeRightAvg> GT #<probeLeftAvg>]]
#<z1PulloffNew> = [#<z1PulloffNew> + #<zOffsetChange>]
o102 endif
(PRINT, New Pulloff Values Prior to Normalizing: Z0=#<z0PulloffNew>, Z1=#<z1PulloffNew>)
(Normalize New Pulloff Values to Minimum Pulloff)
#<change> = 0
o103 if [#<z0PulloffNew> LT #<z1PulloffNew>]
#<change> = [#<minPulloff> - #<z0PulloffNew>]
#<z0PulloffNew> = #<minPulloff>
#<z1PulloffNew> = [#<z1PulloffNew> + #<change>]
o103 elseif [#<z0PulloffNew> GT #<z1PulloffNew>]
#<change> = [#<minPulloff> - #<z1PulloffNew>]
#<z1PulloffNew> = #<minPulloff>
#<z0PulloffNew> = [#<z0PulloffNew> + #<change>]
o103 endif
(PRINT, Z0 Pulloff: Current=#<z0Pulloff>, New=#<z0PulloffNew>)
(PRINT, Z1 Pulloff: Current=#<z1Pulloff>, New=#<z1PulloffNew>)
M0 (PRINT, Continue to Update Pulloff Values)
(Set Pulloff Values)
#</axes/z/motor0/pulloff_mm> = #<z0PulloffNew>
#</axes/z/motor1/pulloff_mm> = #<z1PulloffNew>
(Save Pulloff Values to Config File)
$CD=config.yaml
(PRINT, Z Leveling Complete)
Sure it could do that. Never thought about variation in the trigger.
Hmm, I thought using the G91 inline only applied to that line. Maybe not? Sometimes I think I know just enough to be dangerous so not surprised at all if I’m wrong here.
Yea, that would mess with the calculation.
Will do. This is definitely a better place to sort out the kinks though.
You’re welcome to try modifying it. I won’t be able to try anything until tonight.
Okay this one works, I had to add a X and Z home in the middle to get it right. To speed it up I set it to rapid down 80% for each probe so we could do a slower probe.
(PRINT, LowRider Z Leveling for FluidNC v3.9.1 or higher)
(UPDATE REQUIRED)
#<probeYPos> = 55 (Y position to probe at dependent upon condition of spoilboard)
#<probeXLeftPos> = 5 (Left X position to probe at dependent upon condition of spoilboard)
#<probeXRightPos> = 635 (Right X position to probe at, should be close to max X)
#<xTotalDistance> = 892 (Total X Distance - On LR3, this is from left bearing to Y rail)
#<zMotorLeft> = 0 (Left Z Motor - 0 if Z0 is on the left, 1 if Z1 is on the left)
(UPDATE OPTIONAL)
#<minPulloff> = 4.0 (Minimum pulloff value)
#<jogXYFeedrate> = 1000 (Feedrate for X and Y jogging)
#<jogZFeedrate> = 500 (Feedrate for Z jogging)
#<jogHeight> = 30 (Z height when jogging in X or Y)
#<probeDistance> = -110 (Max probe distance, should be negative)
#<probeFeedrate> = 100 (Feedrate when probing)
#<probeCount> = 3 (Number of times to probe on each side)
#<probeRapidDistance> = [#<probeDistance> * 0.8]
(PRINT, Home All and Initialize)
$H
G21
G90
G94
G92 X0 Y0 Z0
(PRINT, Move to Initial Y Position %d#<probeYPos>)
G00 Y#<probeYPos> F#<jogXYFeedrate>
(PRINT, Move to Initial X Position %d#<probeXLeftPos>)
G00 X#<probeXLeftPos> F#<jogXYFeedrate>
M0 (PRINT, Attach Probe and Probe Left x%d#<probeCount>)
#<probeSum> = 0
o100 repeat [#<probeCount>]
G0 Z#<probeRapidDistance> F#<jogZFeedrate>
G38.2 Z#<probeDistance> F#<probeFeedrate>
#<probeSum> = [#<probeSum> + #5063]
(PRINT, Probe Left Z: #5063)
$HZ F#<jogZFeedrate>
o100 endrepeat
#<probeLeftAvg> = [#<probeSum>/3]
M0 (PRINT, Detach Probe Before Moving to Z%d#<jogHeight> and X%d#<probeXRightPos>)
$HZ F#<probeFeedrate>
$HX
G00 X#<probeXRightPos> F#<jogXYFeedrate>
M0 (PRINT, Re-attach Probe and Probe Right x%d#<probeCount>)
(MSG Probe Right)
#<probeSum> = 0
o101 repeat [#<probeCount>]
G0 Z#<probeRapidDistance> F#<jogZFeedrate>
G38.2 Z#<probeDistance> F#<probeFeedrate>
#<probeSum> = [#<probeSum> + #5063]
(PRINT, Probe Right Z: #5063)
$HZ F#<jogZFeedrate>
o101 endrepeat
#<probeRightAvg> = [#<probeSum>/3]
(PRINT, Z Average: Left=#<probeLeftAvg>, Right=#<probeRightAvg>)
#<zDifference> = [ABS[ABS[#<probeLeftAvg>] - ABS[#<probeRightAvg>]]]
(PRINT, Z Difference: #<zDifference>)
#<xDistance> = [#<probeXRightPos> - #<probeXLeftPos>]
#<zOffsetChange> = [[#<zDifference> / #<xDistance>] * #<xTotalDistance>]
(Get current Z pulloff values)
#<z0Pulloff> = #</axes/z/motor0/pulloff_mm>
#<z1Pulloff> = #</axes/z/motor1/pulloff_mm>
(Calculate New Pulloff Values)
#<z0PulloffNew> = #<z0Pulloff>
#<z1PulloffNew> = #<z1Pulloff>
o102 if [[#<zMotorLeft> EQ 0] AND [#<probeLeftAvg> GT #<probeRightAvg>]]
#<z1PulloffNew> = [#<z1PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 1] AND [#<probeLeftAvg> GT #<probeRightAvg>]]
#<z0PulloffNew> = [#<z0PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 0] AND [#<probeRightAvg> GT #<probeLeftAvg>]]
#<z0PulloffNew> = [#<z0PulloffNew> + #<zOffsetChange>]
o102 elseif [[#<zMotorLeft> EQ 1] AND [#<probeRightAvg> GT #<probeLeftAvg>]]
#<z1PulloffNew> = [#<z1PulloffNew> + #<zOffsetChange>]
o102 endif
(PRINT, New Pulloff Values Prior to Normalizing: Z0=#<z0PulloffNew>, Z1=#<z1PulloffNew>)
(Normalize New Pulloff Values to Minimum Pulloff)
#<change> = 0
o103 if [#<z0PulloffNew> LT #<z1PulloffNew>]
#<change> = [#<minPulloff> - #<z0PulloffNew>]
#<z0PulloffNew> = #<minPulloff>
#<z1PulloffNew> = [#<z1PulloffNew> + #<change>]
o103 elseif [#<z0PulloffNew> GT #<z1PulloffNew>]
#<change> = [#<minPulloff> - #<z1PulloffNew>]
#<z1PulloffNew> = #<minPulloff>
#<z0PulloffNew> = [#<z0PulloffNew> + #<change>]
o103 endif
(PRINT, Z0 Pulloff: Current=#<z0Pulloff>, New=#<z0PulloffNew>)
(PRINT, Z1 Pulloff: Current=#<z1Pulloff>, New=#<z1PulloffNew>)
M0 (PRINT, Continue to Update Pulloff Values)
(Set Pulloff Values)
#</axes/z/motor0/pulloff_mm> = #<z0PulloffNew>
#</axes/z/motor1/pulloff_mm> = #<z1PulloffNew>
(Save Pulloff Values to Config File)
$CD=config.yaml
(PRINT, Z Leveling Complete)
I think if you used these values on an LR3, it would crash into the spoilboard.
Yep. Should be a very small change if it worked right. I’ve also reset the pulloffs to the default values and ran again to see what kind of consistency I get. If things are off, might need to ponder that xTotalDistance value.
It is 80% of whatever your Z probe height is so LR3 should be 85, Lr4 should be 110. That gives them both an extra 5mm.
Does it require a power cycle? I think it does, or at least a reboot?? I am not really sure.
I ran it a few times. I think my right side ends up with a tiny bit more travel each time on average, but before anyone does anymore crazy math let me run a much more controlled test later. I need to tape down the probe to remove my shaking hand.
It is pretty good though my right side was like 0.1mm changes, my left side hit the same exact number several times. I oiled my linear rails, the right side got much more consistent.
This is a hell of a tool Jason, Thank you so much for this. It is super fun. Lots to learn still I am sure.
I didn’t think so but perhaps that should be validated.
It would be really cool if we could figure something out for Y squaring too. I don’t think it has as clean of a solution as this but I still think something is possible. I tried hooking up a tape measure to the endmill to try and make it easier to measure the diagonals. Perhaps something could be 3d printed that you could put in the collet and attached to a tape measure or something. Then maybe a simple calculator in the docs you plug in your values to give you your offsets.
I definitely want both diagonals, not just one. If anything else is not exactly perfect one will just make things worse. Using the difference is better.
I think you have a good idea though, a nice little piece of code like you made here, a couple pauses, all good. We can use a pen of v-bit to make the first corner drive out to the diagonal, pause to take the reading. Come back mark number two, drive out to the other diagonal and pause for a reading.
A calculator with very clear first and second values should make this simple, and fast to verify.
Exactly. I had tried to do something with one diagonal but found that I had some slight variation between jog distance and actual distance. So, measuring both diagonals makes sense.