Position Verification Floor / Ceil inconsistencies.
-
I'm writing some macros that implement protected movements when using a 3D touch probe on a CNC machine.
I have a macro that checks to confirm that the current machine position matches the expected position in one or more of the axes (X, Y, Z).
The code is below:
; G6516.g - CHECK CURRENT POSITION MATCHES ; ; This macro checks if the given position matches the expected position. if { !exists(param.X) && !exists(param.Y) && !exists(param.Z) } abort { "G6516: Must provide at least one of X, Y and Z parameters!" } ; We round to 2 decimal places before comparing M400 ; Check position to 2dp var p = 100 if { exists(param.X) && ((ceil(param.X*var.p) != ceil(move.axes[0].machinePosition*var.p)) && (floor(param.X*var.p) != floor(move.axes[0].machinePosition*var.p))) } abort { "G6516: Machine position does not match expected position - X=" ^ param.X ^ " != " ^ move.axes[0].machinePosition } if { exists(param.Y) && ((ceil(param.Y*var.p) != ceil(move.axes[1].machinePosition*var.p)) && (floor(param.Y*var.p) != floor(move.axes[1].machinePosition*var.p))) } abort { "G6516: Machine position does not match expected position - Y=" ^ param.Y ^ " != " ^ move.axes[1].machinePosition } if { exists(param.Z) && ((ceil(param.Z*var.p) != ceil(move.axes[2].machinePosition*var.p)) && (floor(param.Z*var.p) != floor(move.axes[2].machinePosition*var.p))) } abort { "G6516: Machine position does not match expected position - Z=" ^ param.Z ^ " != " ^ move.axes[2].machinePosition }
This works on my machine using 3.5.0-RC3, which is using an STM32F407 (Spider King). I can move to 100 different random locations and the machine position will always match the expected location to 2 decimal places.
Testing on another board, using the same firmware version (RC3), a Fly CDY-v3 (also STM32F407), this code randomly returns that one of the positions do not match.
My suspicion is that this is caused by a floating point error, or the value of
machinePosition
internally is not what we can see when echoed, but the behaviour that I have found is very odd.I have distilled this down into a file with a value that I know will cause the error on the CDY-v3 but not on the Spider King:
G0 Z0 M400 ; Check position to 2dp var p = 100 ;X=103.0303 != 103.030 var accuracy = 100 var xTest = 103.0303 var xPos = 103.030 G53 G0 X{var.xPos} M400 var xCeil = { ceil(var.xTest * var.accuracy) } var xFloor = { floor(var.xTest * var.accuracy) } var xMPosCeil = { ceil(move.axes[0].machinePosition * var.accuracy) } var xMPosFloor = { floor(move.axes[0].machinePosition * var.accuracy) } var xCeilFail = { var.xCeil != var.xMPosCeil } var xFloorFail = { var.xFloor != var.xMPosFloor } echo { "CEIL: " ^ var.xCeil ^ " == " ^ var.xMPosCeil } echo { "FLOOR: " ^ var.xFloor ^ " == " ^ var.xMPosFloor } echo { "CEIL FAIL: " ^ var.xCeilFail ^ " FLOOR FAIL: " ^ var.xFloorFail } echo { "Failed positioning: " ^ (var.xCeilFail && var.xFloorFail) } echo { "Machine Position: " ^ move.axes[0].machinePosition }
On the Spider King, this shows the following output, as expected:
CEIL: 10304 == 10303 FLOOR: 10303 == 10303 CEIL FAIL: true FLOOR FAIL: false Failed positioning: false Machine Position: 103.030
What is key to this, is that either the
ceil
orfloor
calculation should match if the position is the same.Running this on the CDY-v3, though, outputs this:
CEIL: 10304 == 10303 FLOOR: 10303 == 10302 CEIL FAIL: true FLOOR FAIL: true Failed positioning: true Machine Position: 103.030
Which seems to suggest that
floor(move.axes[0].machinePosition * 100)
is returning a different value on one board when given the same value ofmachinePosition
.I can't think of any other approaches to debug this further - at this point it looks like
floor()
is returning the wrong value for anmachinePosition=103.030 * 100
of10302
which is.... not correct, but runningecho { floor(103.0303 * 100) }
manually returns10303
so this isn't right either.Anyone have any ideas?
-
@NineMile Are you sure that move.axes[0].machinePosition is actually the same each time you are using it? I would capture the value to a local variable once at the start of those tests and use that variable in place of the multiple object model lookups you are doing at the moment. I'd also suggest adding a small delay after the m400, I'm not sure when exactly the machine position is updated it may be that steps are still being generated after the m400 has completed. machinePosition is a little strange in that it is constantly updated during a move, so I'm not sure if it is guaranteed to immediately be correct after an m400 completes.
-
@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
@NineMile Are you sure that move.axes[0].machinePosition is actually the same each time you are using it? I would capture the value to a local variable once at the start of those tests and use that variable in place of the multiple object model lookups you are doing at the moment. I'd also suggest adding a small delay after the m400, I'm not sure when exactly the machine position is updated it may be that steps are still being generated after the m400 has completed. machinePosition is a little strange in that it is constantly updated during a move, so I'm not sure if it is guaranteed to immediately after an m400 completes.
I can't be sure that
move.axes[0].machinePosition
is actually the same (part of the reason for doing it this way in the actualG6516
macro is to reduce the number of variables due to previously discussed memory issues).I know there was a bug in RC2 that meant
machinePosition
was not updated if it had already been updated in the last ~200ms, but I believe that was fixed in RC3, and at least on my Spider King RC3 did resolve the issue for me.I have another piece of code that picks random locations in X and Y, and moves between them at random feed rates, trying to trigger the issue - this also uses the machine position in the same way (separate calls for ceil and floor rather than using a variable) and this code did not trigger incorrectly on the Fly CDY-v3, which leaves me at a bit of a loss.
var max = 10 var accuracy = 100 while { iterations < var.max } ; Generate random locations on X and Y var rX = { random((ceil(move.axes[0].max)*var.accuracy)) } var rY = { random((ceil(move.axes[1].max)*var.accuracy)) } var rF = { 600 + random(1200) } M400 echo {"[" ^ iterations+1 ^ "/" ^ var.max ^ "] Moving to X=" ^ var.rX/var.accuracy ^ " Y=" ^ var.rY/var.accuracy ^ " F=" ^ var.rF} G53 G1 X{var.rX/var.accuracy} Y{var.rY/var.accuracy} F{var.rF} M400 var xCeil = { ceil(var.rX) } var xFloor = { floor(var.rX) } var yCeil = { ceil(var.rY) } var yFloor = { floor(var.rY) } var xMPosCeil = { ceil(move.axes[0].machinePosition * var.accuracy) } var xMPosFloor = { floor(move.axes[0].machinePosition * var.accuracy) } var yMPosCeil = { ceil(move.axes[1].machinePosition * var.accuracy) } var yMPosFloor = { floor(move.axes[1].machinePosition * var.accuracy) } var xFail = { var.xCeil != var.xMPosCeil && var.xFloor != var.xMPosFloor } var yFail = { var.yCeil != var.yMPosCeil && var.yFloor != var.yMPosFloor } ; This should never happen if { var.xFail || var.yFail } echo { "X Expected: " ^ var.xCeil ^ " or " ^ var.xFloor ^ " X Calculated: " ^ var.xMPosCeil ^ " or " ^ var.xMPosFloor } echo { "Y Expected: " ^ var.yCeil ^ " or " ^ var.yFloor ^ " Y Calculated: " ^ var.yMPosCeil ^ " or " ^ var.yMPosFloor } echo { "Failed to position machine." } break echo { "Done, No failure." }
Edit: just to point out, the Fly CDY-v3 is not mine so I can't easily test on it to compare.
-
@NineMile What is it you are trying to do with this? I'm not sure that comparing the machinePosition results against command gcode positions is a good idea. The machinePosiition information is really at a lower level than the coordinates used by normal gcode commands and the two may not always match up, in particular things like tool offsets, babystepping, mesh bed levelling and probably others can result in them being different. You may be better using userPosition. As I think you are finding here I'm also not sure that they are always in sync from a time point of view either.
Getting different results on different printers is not really surprising if the system is still in motion when you sample the position (which I think may be the case here). The time taken to load the gcode file from SD card will vary and there are many tasks running on a RRF system all of which may result in the time you sample the position being slightly different.
I'm not sure if m400 is supposed to ensure that machinePosition is correct before it completes or not. From a gcode point of view it probably only needs to ensure that userPosition is updated.
-
@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
@NineMile What is it you are trying to do with this? I'm not sure that comparing the machinePosition results against command gcode positions is a good idea. The machinePosiition information is really at a lower level than the coordinates used by normal gcode commands and the two may not always match up, in particular things like tool offsets, babystepping, mesh bed levelling and probably others can result in them being different. You may be better using userPosition. As I think you are finding here I'm also not sure that they are always in sync from a time point of view either.
Getting different results on different printers is not really surprising if the system is still in motion when you sample the position (which I think may be the case here). The time taken to load the gcode file from SD card will vary and there are many tasks running on a RRF system all of which may result in the time you sample the position being slightly different.
I'm not sure if m400 is supposed to ensure that machinePosition is correct before it completes or not. From a gcode point of view it probably only needs to ensure that userPosition is updated.
Ok the basis of this is running protected moves during a probing cycle, so that if a touch probe hits something unexpected like a fixture or a clamp the machine will stop moving instead of breaking the probe.
To allow that, we have to use
G38.3
to watch the touch probe status, as under normal circumstances we would expect the probe to not activate. UsingG38.2
, not activating by the time it reaches the target position generates an error that automatically aborts, which is not what we want.So we calculate a number of start and target positions for the probe cycle (e.g. 2 points along each surface for the 2 surfaces that form a corner, for a total of 4 points) based on approximate dimensions of a workpiece, and then use
G38.3
to move towards the start position of each probe.This is all fine, but if the probe is activated during that protected travel move, the machine will stop and is left between the initial position and the start location of the actual probe. Given that
G38.3
does not error when the probe is triggered, that leaves us in a situation where if we were to continue with the probe move it would head towards the target location in an unexpected direction and the probe results would be worthless.That's where the
G6516
macro above comes in - after theG38.3
move towards the starting location, we runG6516
with the co-ordinate that we generated (which can be one or more axes), and check if the machine position matches where we wanted to be before starting the probing move.If we are not in the position we expected, then it is reasonable to assume that the probe was triggered early due to a collision with something unexpected and we abort so the operator has to recover.
What's happening in this situation on the Fly CDY-v3 is that the moves are appearing to work perfectly, and indeed almost all of the time they do, but with particular co-ordinate values it appears that the
G6516
code calculates that the machine is not in the valid position even though the reported machine position is correct, and that appears to be down to some sort of weirdness withmachinePosition
itself, or how it is used byceil()
andfloor()
.To clarify - the moves which we're checking the positioning against are all made in machine co-ordinates so as far as I understand it, these values should match with the object model machine positions once the move has completed, as long as the representations of the values can be massaged into the same format.
-
@NineMile As I said above I think you should probably be using userPosition for all of this, not machinePosition. I think that has a much better defined behaviour model.
I very much doubt if the problem you are seeing is a problem with ceil/floor.
-
@NineMile said in Position Verification Floor / Ceil inconsistencies.:
I know there was a bug in RC2 that meant machinePosition was not updated if it had already been updated in the last ~200ms, but I believe that was fixed in RC3, and at least on my Spider King RC3 did resolve the issue for me.
It's still the case that machinePosition is only updated every 200ms, except that when M400 is used (or another command that waits for motion to stop), then after motion has stopped machinePosition is updated again regardless. So reading machinePosition in a command immediately after M400 will always give the correct value; but reading it at other times when motion is in progress (or has been in progress within the last 200ms) will give a value that it up to 200ms out of date.
-
@dc42 Are all steps complete when m400 returns? Looking at the test program posted in the first post, it looks to me as if there may have been some change in the machinePosition between object model lookups and that was after a m400 had been used.
@NineMile I would suggest that you change your test program to capture each MachinePosition to a local variable and print all of them out at the end. That way we can see if indeed the values are changing. At the moment all we have is speculation.
-
@NineMile Also how are you running this test? Is it being called from an actual print, a macro, from the console?
-
@gloomyandy and do you have move segmentation enabled? If so with what setting?
-
@NineMile I've tried to reproduce this as best I can and it works fine for me. But see the questions above.
Also things which may be impacting the test:
- What is the position of the print head before running your test case?
- What is the feedrate being used for the move?
-
@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
I very much doubt if the problem you are seeing is a problem with ceil/floor.
I very much doubt that too - I should probably update the thread title. I don't think the issue is with
ceil
orfloor
themselves but in how the value is getting to them and producing odd results.@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
@NineMile I would suggest that you change your test program to capture each MachinePosition to a local variable and print all of them out at the end. That way we can see if indeed the values are changing. At the moment all we have is speculation.
All of these were done by running as a gcode file as this is where the problem was seen originally.
Tried this with another CDYv3 using the following code and we were not able to reproduce the issue.
; Move spindle out of the way G0 Z0 ; Move table all the way to the right, although start position does not appear to matter G0 X0 M400 var accuracy = 100 var xTest = 103.0303 var xPos = 103.030 G53 G0 X{var.xPos} ; No more moves after this, all positions should be accurate M400 var xCeil = { ceil(var.xTest * var.accuracy) } var xFloor = { floor(var.xTest * var.accuracy) } var xMPos1 = { move.axes[0].machinePosition } echo { "X1=" ^ var.xMPos1 } var xMPosCeil = { ceil(var.xMPos1 * var.accuracy) } var xMPos2 = { move.axes[0].machinePosition } echo { "X2=" ^ var.xMPos2 } var xMPosFloor = { floor(var.xMPos2 * var.accuracy) } var xCeilFail = { var.xCeil != var.xMPosCeil } var xFloorFail = { var.xFloor != var.xMPosFloor } echo { "CEIL: " ^ var.xCeil ^ " ?= " ^ var.xMPosCeil } echo { "FLOOR: " ^ var.xFloor ^ " ?= " ^ var.xMPosFloor } echo { "CEIL FAIL: " ^ var.xCeilFail ^ " FLOOR FAIL: " ^ var.xFloorFail } echo { "Failed positioning: " ^ (var.xCeilFail && var.xFloorFail) } echo { "Final Machine Position: " ^ move.axes[0].machinePosition }
The output for non-reproduction of the issue:
X1=103.030 X2=103.030 CEIL: 10304 ?= 10303 FLOOR: 10303 ?= 10303 CEIL FAIL: true FLOOR FAIL: false Failed positioning: false Final Machine Position: 103.030 Finished printing file 0:/gcodes/position-test-2.gcode, print time was 0h 0m
Again, this only fails if both FLOOR and CEIL comparisons do not match.
We then tried the original code from my first post (the non looping one) and that was unable to reproduce the issue as well.
@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
@gloomyandy and do you have move segmentation enabled? If so with what setting?
I have segmentation enabled with
S5 T0.5
and am not seeing the issue. The machine we were able to reproduce this on has noM669
line so I assume defaults to segmentation disabled.The guy with the machine that this can be reproduced on can't run more tests at the moment but I'll update when I have more info.
@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
@NineMile I've tried to reproduce this as best I can and it works fine for me. But see the questions above.
Also things which may be impacting the test:
- What is the position of the print head before running your test case?
- What is the feedrate being used for the move?
The spindle doesn't move except in Z, where it is stationary at Z=0 (top). The table position does not appear to matter either, my code has been moving it to X0 just so there's a long move before testing the location but it also appeared with random starting locations, or the machine parking location (which is half the length of X, and should involve the machine moving in the opposite direction to the target location).
The moves are G0's and my machine limits (unreproducible) are 2000mm/min on X, on the reproducible board they're 2800mm/min, but when using the probe move itself these are 1200 or 300mm/min so it appears to be happening at multiple feed rates.
Just want to say thanks @gloomyandy for trying to help reproduce, this one has been frying my head for days and I appreciate the input and thoughts - I'll hopefully have a properly logged reproduction from the affected machine soon.
-
@NineMile I would also check that the machine that is showing the problem is actually running 3.5 rc3 (get a M122 output from it, unfortunately people sometimes get things wrong).
-
@gloomyandy said in Position Verification Floor / Ceil inconsistencies.:
@NineMile I would also check that the machine that is showing the problem is actually running 3.5 rc3 (get a M122 output from it, unfortunately people sometimes get things wrong).
This was the first thing I asked for as I thought the issue was the machinePosition update delay on RC2 and below. It's definitely on RC3 and we're looking to test on more boards soon.