Determining Max Speed and Acceleration

There is a very handy guide for calculating the Max Speed and Acceleration your printer can handle here except the macro that it offers is aimed at klipper.
I created 2 macros that do the same thing, one for coreXY printers and one for cartesian printers.
These can be used in conjunction with the klipper guide.coreXY
; parameters ; A = maximum speed in mm/s ; B = maximum acceleration in mm/s2 ; C = iterations ; D = Bound Size in mm ; E = smallPatternSize in mm ; Set up local variables var speedXCurrent = move.axes[0].speed var speedYCurrent = move.axes[1].speed var accelerationXCurrent = move.axes[0].acceleration var accelerationYCurrent = move.axes[1].acceleration var speedX = 0 var speedY = 0 var accelerationX = 0 var accelerationY = 0 var macroIterations = 0 var bound = 0 var smallPatternSize = 0 var xPositionStart = 0 var yPositionStart = 0 var xPositionEnd = 0 var yPositionEnd = 0 var xEndstopHigh = sensors.endstops[0].highEnd var yEndstopHigh = sensors.endstops[1].highEnd var xPositionDifference = 0 var yPositionDifference = 0 var xMMPerFullStep = 0 var yMMPerFullStep = 0 if !exists(param.A) set var.speedX = move.axes[0].speed / 60 set var.speedY = move.axes[1].speed / 60 else set var.speedX = param.A set var.speedY = param.A if !exists(param.B) set var.accelerationX = move.axes[0].acceleration set var.accelerationY = move.axes[1].acceleration else set var.accelerationX = param.B set var.accelerationY = param.B if !exists(param.C) set var.macroIterations = 5 else set var.macroIterations = param.C if !exists(param.D) set var.bound = 20 else set var.bound = param.D if !exists(param.E) set var.smallPatternSize = 20 else set var.smallPatternSize = param.E ; Large Pattern var x_min = move.axes[0].min + var.bound var x_max = move.axes[0].max  var.bound var y_min = move.axes[1].min + var.bound var y_max = move.axes[1].max  var.bound ; Small Pattern at Centre var x_centre = ( move.axes[0].max  move.axes[0].min ) / 2 var y_centre = ( move.axes[1].max  move.axes[1].min ) / 2 ; Set Small Pattern Box Around Centre Point var x_centre_min = var.x_centre  (var.smallPatternSize/2) var x_centre_max = var.x_centre + (var.smallPatternSize/2) var y_centre_min = var.y_centre  (var.smallPatternSize/2) var y_centre_max = var.y_centre + (var.smallPatternSize/2) M118 P0 S"Starting Speed Test" ; Home and get position for comparison later G28 G32 G90 if var.xEndstopHigh G0 X{move.axes[0].max  1} F1800 else G0 X{move.axes[0].min + 1} F1800 if var.yEndstopHigh G0 Y{move.axes[1].max  1} F1800 else G0 Y{move.axes[1].min + 1} F1800 M400 G4 S1 set var.xPositionStart = move.axes[0].machinePosition set var.yPositionStart = move.axes[1].machinePosition echo "Start X Position is " ^ var.xPositionStart echo "Start Y Position is " ^ var.yPositionStart ; Set New Limits ; Speeds M203 X{var.speedX*60} Y{var.speedY*60} ; Accelerations M201 X{var.accelerationX} Y{var.accelerationY} ; Go to Start Position G0 X{var.x_min} Y{var.y_min} Z{var.bound + 10} F{var.speedX*60} ; Movement while iterations < var.macroIterations ; Large Pattern ; Diagonals G0 X{var.x_min} Y{var.y_min} F{var.speedX*60} G0 X{var.x_max} Y{var.y_max} F{var.speedX*60} G0 X{var.x_min} Y{var.y_min} F{var.speedX*60} G0 X{var.x_max} Y{var.y_min} F{var.speedX*60} G0 X{var.x_min} Y{var.y_max} F{var.speedX*60} G0 X{var.x_max} Y{var.y_min} F{var.speedX*60} ; Box G0 X{var.x_min} Y{var.y_min} F{var.speedX*60} G0 X{var.x_min} Y{var.y_max} F{var.speedX*60} G0 X{var.x_max} Y{var.y_max} F{var.speedX*60} G0 X{var.x_max} Y{var.y_min} F{var.speedX*60} ; Small Pattern ; Diagonals G0 X{var.x_centre_min} Y{var.y_centre_min} F{var.speedX*60} G0 X{var.x_centre_max} Y{var.y_centre_max} F{var.speedX*60} G0 X{var.x_centre_min} Y{var.y_centre_min} F{var.speedX*60} G0 X{var.x_centre_max} Y{var.y_centre_min} F{var.speedX*60} G0 X{var.x_centre_min} Y{var.y_centre_max} F{var.speedX*60} G0 X{var.x_centre_max} Y{var.y_centre_min} F{var.speedX*60} ; Box G0 X{var.x_centre_min} Y{var.y_centre_min} F{var.speedX*60} G0 X{var.x_centre_min} Y{var.y_centre_max} F{var.speedX*60} G0 X{var.x_centre_max} Y{var.y_centre_max} F{var.speedX*60} G0 X{var.x_centre_max} Y{var.y_centre_min} F{var.speedX*60} ; Restore Limits ; Speeds M203 X{var.speedXCurrent} Y{var.speedYCurrent} ; Accelerations M201 X{var.accelerationXCurrent} Y{var.accelerationYCurrent} ; Go back to 1mm from endstops and measure distance to endstop for Comparison G90 if var.xEndstopHigh G0 X{move.axes[0].max  1} F1800 M400 G4 S1 G91 G1 H4 X{move.axes[0].max} F60 G90 M400 G4 S1 set var.xPositionEnd = move.axes[0].machinePosition  1 else G0 X{move.axes[0].min + 1} F1800 M400 G4 S1 G91 G1 H4 X{move.axes[0].max} F60 G90 M400 G4 S1 set var.xPositionEnd = move.axes[0].machinePosition + 1 if var.yEndstopHigh G0 Y{move.axes[1].max  1} F1800 M400 G4 S1 G91 G1 H4 Y{move.axes[1].max} F60 M400 G4 S1 set var.yPositionEnd = move.axes[1].machinePosition  1 else G0 Y{move.axes[1].min + 1} F1800 M400 G4 S1 G91 G1 H4 Y{move.axes[1].max} F60 M400 G4 S1 set var.yPositionEnd = move.axes[1].machinePosition + 1 echo "End X Position is " ^ var.xPositionEnd echo "End Y Position is " ^ var.yPositionEnd set var.xPositionDifference = abs(var.xPositionStart  var.xPositionEnd) set var.yPositionDifference = abs(var.yPositionStart  var.yPositionEnd) echo "X difference is " ^ var.xPositionDifference echo "Y difference is " ^ var.yPositionDifference set var.xMMPerFullStep = (1 / move.axes[0].stepsPerMm) + (1 / move.axes[0].stepsPerMm / move.axes[0].microstepping.value) set var.yMMPerFullStep = (1 / move.axes[1].stepsPerMm) + (1 / move.axes[1].stepsPerMm / move.axes[1].microstepping.value) if var.xPositionDifference >= var.xMMPerFullStep M118 P0 S"There has been some skipping detected on the X axis. Please lower your acceleration or speed and test again" else M118 P0 S"There has been no skipping detected on the X axis" if var.yPositionDifference >= var.yMMPerFullStep M118 P0 S"There has been some skipping detected on the Y axis. Please lower your acceleration or speed and test again" else M118 P0 S"There has been no skipping detected on the Y axis"
cartesian
; parameters ; A = maximum speed in mm/s ; B = maximum acceleration in mm/s2 ; C = iterations ; D = Bound Size in mm ; E = smallPatternSize in mm ; F = Axis to be tested, either F"X" or F"Y" is valid ; Set up local variables var speedXCurrent = move.axes[0].speed var speedYCurrent = move.axes[1].speed var accelerationXCurrent = move.axes[0].acceleration var accelerationYCurrent = move.axes[1].acceleration var speedX = 0 var speedY = 0 var accelerationX = 0 var accelerationY = 0 var macroIterations = 0 var bound = 0 var smallPatternSize = 0 var testAxis = 0 var xPositionStart = 0 var yPositionStart = 0 var xPositionEnd = 0 var yPositionEnd = 0 var xEndstopHigh = sensors.endstops[0].highEnd var yEndstopHigh = sensors.endstops[1].highEnd var xPositionDifference = 0 var yPositionDifference = 0 var xMMPerFullStep = 0 var yMMPerFullStep = 0 if !exists(param.A) set var.speedX = move.axes[0].speed / 60 set var.speedY = move.axes[1].speed / 60 else set var.speedX = param.A set var.speedY = param.A if !exists(param.B) set var.accelerationX = move.axes[0].acceleration set var.accelerationY = move.axes[1].acceleration else set var.accelerationX = param.B set var.accelerationY = param.B if !exists(param.C) set var.macroIterations = 5 else set var.macroIterations = param.C if !exists(param.D) set var.bound = 20 else set var.bound = param.D if !exists(param.E) set var.smallPatternSize = 20 else set var.smallPatternSize = param.E if !exists(param.F) abort "No Axis has been set using parameters" elif param.F = "X" set var.testAxis = 0 elif param.F = "Y" set var.testAxis = 1 else abort "Only X or Y axis can be used" ; Large Pattern var x_min = move.axes[0].min + var.bound var x_max = move.axes[0].max  var.bound var y_min = move.axes[1].min + var.bound var y_max = move.axes[1].max  var.bound ; Small Pattern at Centre var x_centre = ( move.axes[0].max  move.axes[0].min ) / 2 var y_centre = ( move.axes[1].max  move.axes[1].min ) / 2 ; Set Small Pattern Box Around Centre Point var x_centre_min = var.x_centre  (var.smallPatternSize/2) var x_centre_max = var.x_centre + (var.smallPatternSize/2) var y_centre_min = var.y_centre  (var.smallPatternSize/2) var y_centre_max = var.y_centre + (var.smallPatternSize/2) M118 P0 S"Starting Speed Test" ; Home and get position for comparison later G28 G32 G90 if var.testAxis = 0 if var.xEndstopHigh G0 X{move.axes[0].max  1} F1800 else G0 X{move.axes[0].min + 1} F1800 M400 G4 S1 set var.xPositionStart = move.axes[0].machinePosition echo "Start X Position is " ^ var.xPositionStart if var.testAxis = 1 if var.yEndstopHigh G0 Y{move.axes[1].max  1} F1800 else G0 Y{move.axes[1].min + 1} F1800 M400 G4 S1 set var.yPositionStart = move.axes[1].machinePosition echo "Start Y Position is " ^ var.yPositionStart ; Set New Limits ; Speeds M203 X{var.speedX*60} Y{var.speedY*60} ; Accelerations M201 X{var.accelerationX} Y{var.accelerationY} ; Go to Start Position if var.testAxis = 0 G0 X{var.x_min} Z{var.bound + 10} F{var.speedX*60} if var.testAxis = 1 G0 Y{var.y_min} Z{var.bound + 10} F{var.speedX*60} if var.testAxis = 0 ; Movement while iterations < var.macroIterations ; Large Pattern ; Large Line G0 X{var.x_min} F{var.speedX*60} G0 X{var.x_max} F{var.speedX*60} G0 X{var.x_min} F{var.speedX*60} G0 X{var.x_max} F{var.speedX*60} ; Small Pattern ; Small Line G0 X{var.x_centre_min} F{var.speedX*60} G0 X{var.x_centre_max} F{var.speedX*60} G0 X{var.x_centre_min} F{var.speedX*60} G0 X{var.x_centre_max} F{var.speedX*60} if var.testAxis = 1 ; Movement while iterations < var.macroIterations ; Large Pattern ; Large Line G0 Y{var.y_min} F{var.speedX*60} G0 Y{var.y_max} F{var.speedX*60} G0 Y{var.y_min} F{var.speedX*60} G0 Y{var.y_max} F{var.speedX*60} ; Small Pattern ; Small Line G0 Y{var.y_centre_min} F{var.speedX*60} G0 Y{var.y_centre_max} F{var.speedX*60} G0 Y{var.y_centre_min} F{var.speedX*60} G0 Y{var.y_centre_max} F{var.speedX*60} ; Restore Limits ; Speeds M203 X{var.speedXCurrent} Y{var.speedYCurrent} ; Accelerations M201 X{var.accelerationXCurrent} Y{var.accelerationYCurrent} ; Go back to 1mm from endstops and measure distance to endstop for Comparison if var.testAxis = 0 if var.xEndstopHigh G0 X{move.axes[0].max  1} F1800 M400 G4 S1 G91 G1 H4 X{move.axes[0].max} F60 G90 M400 G4 S1 set var.xPositionEnd = move.axes[0].machinePosition  1 else G0 X{move.axes[0].min + 1} F1800 M400 G4 S1 G91 G1 H4 X{move.axes[0].max} F60 G90 M400 G4 S1 set var.xPositionEnd = move.axes[0].machinePosition + 1 G90 echo "End X Position is " ^ var.xPositionEnd set var.xPositionDifference = abs(var.xPositionStart  var.xPositionEnd) echo "X difference is " ^ var.xPositionDifference set var.xMMPerFullStep = (1 / move.axes[0].stepsPerMm) + (1 / move.axes[0].stepsPerMm / move.axes[0].microstepping.value) ; set the check value to a full step + 1 microstep. mainly due to round with only 3 decemal places if var.xPositionDifference >= var.xMMPerFullStep M118 P0 S"There has been some skipping detected on the X axis. Please lower your acceleration or speed and test again" else M118 P0 S"There has been no skipping detected on the X axis" if var.testAxis = 1 if var.yEndstopHigh G0 Y{move.axes[1].max  1} F1800 M400 G4 S1 G91 G1 H4 Y{move.axes[1].max} F60 M400 G4 S1 set var.yPositionEnd = move.axes[1].machinePosition  1 else G0 Y{move.axes[1].min + 1} F1800 M400 G4 S1 G91 G1 H4 Y{move.axes[1].max} F60 M400 G4 S1 set var.yPositionEnd = move.axes[1].machinePosition + 1 echo "End Y Position is " ^ var.yPositionEnd set var.yPositionDifference = abs(var.yPositionStart  var.yPositionEnd) echo "Y difference is " ^ var.yPositionDifference set var.yMMPerFullStep = (1 / move.axes[1].stepsPerMm) + (1 / move.axes[1].stepsPerMm / move.axes[1].microstepping.value) ; set the check value to a full step + 1 microstep. mainly due to round with only 3 decemal places if var.yPositionDifference >= var.yMMPerFullStep M118 P0 S"There has been some skipping detected on the Y axis. Please lower your acceleration or speed and test again" else M118 P0 S"There has been no skipping detected on the Y axis"
Both of these scripts accept parameters to adjust the settings (and these are listed at the top of each macro). Once they have ran, they will tell you whether a skip of more than 1 full step has occurred.
The macros will automatically work regardless of whether your endstops are low or high.
The cartesian macro will abort if an axis (X or Y) is not passed through as a parameter.
If no other parameters are used, the default config.g settings will be used.
If custom parameters are used, the default config.g settings will be restored at the end of the macro.Warning 1: They won't work with sensorless homing based printers unless you edit the scripts to include all the correct settings just above the G1 H4 measurement moves
Warning 2: If the moves commanded have too high acceleration or speed they will skip. There is no protection against this and you may damage your printer. Make sure you are prepared to press the emergency stop button whilst running this
I'm interested in any feedback people have and whether the scripts work ok for you.
Both have been tested on 3.4.5 and should be fine on 3.5betaX 
@jay_s_uk I'll certainly give that a shot when I get my printer built. As per our chat, I'll be using remote drive shafts so it'll be interesting to run comparisons using 20 tooth to 20 tooth pulleys, and 20 tooth to 40 tooth. The latter will in theory double the mechanical torque on the drive shaft but that may all be negated by losses due to a doubling of motor rotational speed. As discussed, the torque curve for the motor indicates a loss of 30% torque but the gearing effect will double that when applied to the drive shaft. So in theory there will be a net gain in torque at the drive shaft of 140% but back EMF could be the killer. It'll be interesting to see what the macro shows.


Hi Jay. I finally got around to testing this macro (the CoreXY version). Feedback as follows...........

I had error messages relating to G30 Z probe not found. That'll be because I don't have one Couldn't see any G30 in the macro but there was a G32 that I commented out and which cured the error. I don't see that we need to run bed.g on a CoreXY to check for motor skipping.

The console shows errors "Warning: both space and tab characters used to indent blocks at/before line 223". That may be because I copied and pasted the code from your post into notepad++ and then saved it but I'm buggered if I can see where the issue might be. I deleted all the indentation and replaced it with single tabs but the warning persists. Anyway, it seems it's just a minor warning.

It looked like my "small pattern" was being printed at the back right corner and I guess it should have been in the centre? Methinks that might be because I use the centre of the bed as the origin. So my axis limits for X are 192 to +192 and for Y they are 219 to +199. In your code you have var x_centre = ( move.axes[0].max  move.axes[0].min ) / 2 which for X, equate to 192 minus  192 (double minus = +) so 384 / 2 = 192. But 192 is X max, not the origin (which is 0,0). That's easy enough for me to change on my machine but you might want to catch this if you want a "universal" macro.

I had to look up the use of parameters in meta commands. Just an observation for anyone else who might want to try Jay's macros but once you've saved the file then call it using the format M98 P"0:/macros/speedTest.g" A300 B2000 C2. The parameters are listed at the top of the macro so in that example, I called it and passed the speed (A) of 300 and acceleration (B) of 2000 to the macro.

The test results were a bit weird and seemingly inconsistent.
5.1 First test  speed 300, acceleration 2000. Result X difference is 0.013
Y difference is 0.113.5.2 Second test  speed reduced to 200, acceleration retained at 2000. Result X difference is 0.025 Y difference is 0.050 (Y better, X worse).
5.3. Third test  speed retained at 200, acceleration reduced to 1000. Result X difference is 0.050 Y difference is 0.037 (X worse, Y better).
5.4. Forth test  silly slow speed 150 and accel of 500. Result X difference is 0.050 Y difference is 0.000. So X the same, Y better but Y is the by far the greater mass so that makes no sense.
5.5. Fifth test. Speed 300, accel 5000. According to the calculator, this speed should be borderline for back emf due to rotation, and the motors should struggle accelerating my heavyish mass at this rate. Result X difference is 0.025
Y difference is 0.012. One of the best results so far which makes no sense given that other tests indicated I should lower the speed and or acceleration. Again, X is worse than Y which makes no sense either.5.6. Sixth test. Speed 400, accel 5,000  kind of silly high for my highish moving mass but surprisingly it looked and sounded just fine. I thought my other printer was pretty rigid but this one is rock solid. Anyway, result X difference is 0.000 Y difference is 0.125. This is kind of believable in that Y is at least worse than X but it makes no sense in that when I tested at both slower speeds and lower accelerations, the recommendation was to reduce one or both.
 Observational comments. I'd say that there is either some sort of repeatability issue from test to test, or that the threshold for detecting missed steps is too sensitive. I'm pretty sure it isn't anything mechanical as there ought to be a bigger difference between "silly slow" and "silly fast". In fact, the best result for the X axis was at "silly fast".
Having said all that, looking back at point 3 above (bed origin), it occurs to me that the small pattern would have run up against the axis limits so some moves would have been truncated  might that have affected the results?


@deckingman thanks for that response. I agree I should probably make the parameter description better.
I need to look and see what I can do to make the repeatability better. With klipper you can see the step position whereas we don't have that with marlin so what the script does is homes, moves back by 1mm and then records that position. It then does the test moves, goes back to that saved position and then measure how far it has to move until it triggers the endstops. I couldn't think of any other way of doing it with RRF unless you have any ideas?I'll see what I can do to make the script more universal in terms of the origin (I hadn't thought about that). I can also put a check in to see whether the probe exists. The bed levelling is mostly there for vorons where the gantry drops.
@Falcounet was also going to look at adding some repeatability tests in for the endstops so I'll check in with him.
The criteria for whether a skip is detected is 1 full step so maybe this is a little tight (it calculates what a step equals and I think I have to go slightly higher due to decimal places).
But thanks for your feedback and I'll look at updating it

@jay_s_uk No worries. Thinking about it some more, I reckon for a CoreXY, it would be better just to do rapid 45 degree moves. With anything else, we have two motors contributing to motion so all sorts of interactions going on. If we are just concerned about missed steps, then we should concentrate on doing each motor individually don't you think? So maybe two macros  the first one does Xmin Ymin to Xmax Ymax thus exercising just the Alpha motor, the second doing Xmax Ymin to Xmin Ymax  i.e the Beta motor. Single motor moves on a CoreXY would be the worse case so that's what the machine limits should be set to  even though other moves might use both motors.
EDIT. Xmin Ymin to Xmax Ymax is only 45 degrees if the axes lengths are the same for X and Y. So you'd need to see which axis has the shortest travel distance and apply this distance to both axes, i.e. from Xmin Ymin to Xmin+travelDistance Ymin+travelDistance.

@deckingman RRF automatically reduces the maximum speed for 45 degree moves (unlike Klipper). So it shouldn't matter whether you do X and Y moves or 45 degree moves. Preferably, do both.
This also means that on a CoreXY machine the maximum X and Y speeds should be set 1.4 times higher than for Klipper on the same machine.

@dc42 I was just thinking that if the objective is to look for skipped steps caused by high speed and/ or high acceleration, then the worse case scenario would be if all the load was on one motor. Hence front left to rear right at 45 degrees to exercise only the Alpha motor, and front right to rear left at 45 degree to exercise only the Beta motor.

@deckingman said in Determining Max Speed and Acceleration:
I was just thinking that if the objective is to look for skipped steps caused by high speed and/ or high acceleration, then the worse case scenario would be if all the load was on one motor
If the macro works by setting the M203 X and Y values very high and then trying G1 commands at different speeds, then you are right. If instead it works by adjusting the M203 X and Y values at each step and then commanding G1 moves at or above those speeds, then RRF will automatically reduce the speed if it's a diagonal move, so the direction you choose shouldn't matter.

@dc42 The macro that @jay_s_uk posted takes speed and acceleration inputs ,then performs a series of moves using those same values. The idea behind it is to run the macro multiple times, each time with higher speed and/or acceleration. As far as I can work out, it then returns the print head to its original start position (which was determined as being 1mm away from the end stops) then measures how far the print head has to move until the end stop triggers. The difference between the start and end positions being used as a measure of any skipped steps. So my point is that the pure X or pure Y moves would share the load between both motors and so those moves would be less likely to suffer skipped steps than single motor moves.

@jay_s_uk Hi Jay. I hacked your macro around in order to test endstop repeatability. It's specific to my machine (Y homes to max, origin is in the centre of the bed). It does essentially what your macro did but replaces the entire move section with a simple, slowish speed move. So it homes just X and Y (no point doing Z) at 60mm/minute, establishes the start position, moves 10mm away from both end stops at 1800 mm/minute (30mm/sec), then establishes the end positions and differences just like you were doing. Then it increases the homing speed by 60mm/sec and repeats the process.
Here is the code
var xPositionStart = 0 var yPositionStart = 0 var xPositionEnd = 0 var yPositionEnd = 0 var xPositionDifference = 0 var yPositionDifference = 0 var feedRate = 60 var feedRateStep = 60 while iterations <10 G28 XY ; home just X and Y G91; relative G0 X{move.axes[0].min + 1} F1800 M400 G0 Y{move.axes[1].max  1} F1800 M400 set var.xPositionStart = move.axes[0].machinePosition; set X start position set var.yPositionStart = move.axes[1].machinePosition ; set Y start position G1 X10 Y10 F1800; move away 10mm @ 30mm/sec M400; wait for move to finish ; Go back to 1mm from endstops and measure distance to endstop for Comparison G90; absolute G0 X{move.axes[0].min + 1} F1800 M400 G91 ; relative G1 H4 X{move.axes[0].max} F{var.feedRate} M400 G4 S1 set var.xPositionEnd = move.axes[0].machinePosition + 1 G90;absolute G0 Y{move.axes[1].max  1} F1800 M400 G4 S1 G91; relative G1 H4 Y{move.axes[1].max} F{var.feedRate} M400 G4 S1 set var.yPositionEnd = move.axes[1].machinePosition  1 set var.xPositionDifference = abs(var.xPositionStart  var.xPositionEnd) set var.yPositionDifference = abs(var.yPositionStart  var.yPositionEnd) echo "X difference is " ^ var.xPositionDifference, " at homing feedrate of " ^ var.feedRate, " mm/minute" echo "Y difference is " ^ var.yPositionDifference, " at homing feedrate of " ^ var.feedRate, " mm/minute" set var.feedRate = var.feedRate + var.feedRateStep
......and here is the console readout from running it............
23/07/2023, 12:22:47 X difference is 0.250 at homing feedrate of 600 mm/minute
Y difference is 0.100 at homing feedrate of 600 mm/minute
23/07/2023, 12:22:15 X difference is 0.050 at homing feedrate of 540 mm/minute
Y difference is 0.088 at homing feedrate of 540 mm/minute
23/07/2023, 12:21:42 X difference is 0.188 at homing feedrate of 480 mm/minute
Y difference is 0.100 at homing feedrate of 480 mm/minute
23/07/2023, 12:21:10 X difference is 0.050 at homing feedrate of 420 mm/minute
Y difference is 0.100 at homing feedrate of 420 mm/minute
23/07/2023, 12:20:38 X difference is 0.050 at homing feedrate of 360 mm/minute
Y difference is 0.113 at homing feedrate of 360 mm/minute
23/07/2023, 12:20:05 X difference is 0.038 at homing feedrate of 300 mm/minute
Y difference is 0.100 at homing feedrate of 300 mm/minute
23/07/2023, 12:19:33 X difference is 0.038 at homing feedrate of 240 mm/minute
Y difference is 0.137 at homing feedrate of 240 mm/minute
23/07/2023, 12:19:00 X difference is 0.025 at homing feedrate of 180 mm/minute
Y difference is 0.125 at homing feedrate of 180 mm/minute
23/07/2023, 12:18:27 X difference is 0.212 at homing feedrate of 120 mm/minute
Y difference is 0.062 at homing feedrate of 120 mm/minute
23/07/2023, 12:17:54 M98 P"0:/macros/endStopRepeatability.g"
X difference is 0.062 at homing feedrate of 60 mm/minute
Y difference is 0.038 at homing feedrate of 60 mm/minuteSo it looks like my homing microswitches have a repeatability of up to 0.25mm (worse case). That's fine for homing purposes but not good for determining precise positioning errors. No doubt, slotted opto switches would be more repeatable but I doubt too many people would want to change their otherwise perfectly acceptable microswitches just for the purpose of establishing their machines' maximum capabilities.
So I guess a valid approach might be to only flag the possibility of missed steps if the positional difference is greater than the repeatability error for the switch. In my case, I could only say that there is a high likelihood of skipped steps if the difference between start and end is greater than 0.25 mm. The trouble is, at 80 steps per mm for my X and Y axes, 0.25mm equates to 20 full steps. But then I guess if you push the envelope and get into genuine skipped step territory, you are likely to see more than 20 missed steps so maybe it's still a valid approach? Dunno......
EDIT. The error at 120mm/minute (2mm/sec) homing speed is much the same as the error at 600mm/minute (10mm/sec) so slow homing speed doesn't help repeatability (although it could be even worse at higher homing speeds).

@deckingman Interesting, a few questions so I can get my head around what is going on...
You mention "it homes just X and Y (no point doing Z) at 60mm/minute". It looks like you are using G28 to set the initial position, is the feedrate in your homex.g/homey.g for the final homing move 60mm/min?
It looks like the final H4 move is only 1mm is that correct? What acceleration is being used for that move? Does it allow the target speed to be reached over a 1mm move?
Looking at the initial output:
23/07/2023, 12:17:54 M98 P"0:/macros/endStopRepeatability.g"
X difference is 0.062 at homing feedrate of 60 mm/minute
Y difference is 0.038 at homing feedrate of 60 mm/minuteIt seems like at that speed the repeatability might be better? I wonder if you ran multiple iterations at that single speed you would still see the odd spike in the error? I wonder if having this speed match the speed used in the homing files has any impact on things?

@gloomyandy TBH, I just hacked Jay's original macro without looking too deeply at what's going on. But I'll do my best to answer your questions.
 The second pass of my home X and home Y use a feed rate of 360 (so 6mm/sec).
 My default accelerations for x and Y are set to 1000 mm/sec^2 and neither this macro nor my homing files change that so I guess that's what's being used. My maths is a bit rusty these days but I reckon accel of 1000 mm/sec^2 should lead to a maximum speed of 31.6 mm/sec over a distance of 1mm.
 I guess what might be a pertinent test would be to run multiple iterations at a fixed speed of 360 which is the same as the second pass of the initial homing moves. So final home both axes at 360, move away, then move back to end stops all at the same speed, and repeat.
That'll be easy enough to do  I'll get on with it shortly when I've finished what I'm doing with the machine.

@deckingman I make it 44.72mm/s (cheating by using this: http://instantphysics.com/motion/equationsofmotion/). But either way that should not be an issue!
Yes I agree that a test using the same speed for the homing moves and the position detection would be interesting!
I'd try it myself but the only (working) printers I have use sensorless homing which is a bit of a non starter for this sort of thing.

@gloomyandy too late  I've already done it at 360mm/min(6mm/sec).
I did two runs. The first was 10 iterations, the second was 20.
For some reason, I can't download the console output so I've copied and pasted it into notepad.
One could play some statistical tricks and pick a sequence of 4 or 5 out of the data set and discard the other 15 or 16 readings as outliers, but even that sort of outrageous manipulation will still show a repeatability error of around 0.03 which is around 3 full steps.
I'm not at all surprised to find that a cheap mechanical microswitch is only accurate to around 0.2mm. That's more than good enough for basic homing.
Maybe Jay's original macro is fundamentally OK but one would need to allow for these switch repeatability errors. So one could only say with confidence that missed steps were detected if the difference in position was greater than (say) 0.2mm.
Having said all that, I've just noticed that all the differences are positive. A quick gander at Jay's file (which I largely copied) shows that we are using the abs function.
I'll take that abs function out and run one more test so that we can see if the differences are all positive, all negative, or a mixture of both.

Well I suppose one could say that X is always negative and Y is always positive and that if one thought about it hard enough and for long enough, there might be a reason for that. But it doesn't get away from the fact that 1 microstep is 0.0125mm and a cheap mechanical microswitch ain't gonna be accurate enough.
23/07/2023, 17:55:43 X difference is 0.038 at homing feedrate of 360 mm/minute
Y difference is 0.050 at homing feedrate of 360 mm/minute
23/07/2023, 17:55:06 X difference is 0.025 at homing feedrate of 360 mm/minute
Y difference is 0.075 at homing feedrate of 360 mm/minute
23/07/2023, 17:54:29 X difference is 0.038 at homing feedrate of 360 mm/minute
Y difference is 0.075 at homing feedrate of 360 mm/minute
23/07/2023, 17:53:52 X difference is 0.013 at homing feedrate of 360 mm/minute
Y difference is 0.088 at homing feedrate of 360 mm/minute
23/07/2023, 17:53:15 X difference is 0.038 at homing feedrate of 360 mm/minute
Y difference is 0.062 at homing feedrate of 360 mm/minute
23/07/2023, 17:52:01 X difference is 0.025 at homing feedrate of 360 mm/minute
Y difference is 0.087 at homing feedrate of 360 mm/minute
23/07/2023, 17:51:24 X difference is 0.212 at homing feedrate of 360 mm/minute
Y difference is 0.087 at homing feedrate of 360 mm/minute
23/07/2023, 17:50:47 X difference is 0.212 at homing feedrate of 360 mm/minute
Y difference is 0.113 at homing feedrate of 360 mm/minute
23/07/2023, 17:50:10 M98 P"0:/macros/endStopRepeatability.g"
X difference is 0.087 at homing feedrate of 360 mm/minute
Y difference is 0.150 at homing feedrate of 360 mm/minute 

