TinyG skipped a job's last short move and reported it done
If a TinyG job ended with a very short move made at speed, the board could skip that move and still report the tool at the programmed endpoint. The same happened just before a dwell, an M5, a G92 or a probe. The error is at most the feed rate times 2.5 milliseconds: about 0.03 mm at F800, 0.1 mm at F2400, 0.6 mm at a 15 m/min rapid. Every TinyG build has it, including master 440.21 and the 450.03 release. It is fixed on edge-next in commit a3b4e6b3 (issue #301).
- 21steps never sent in our test
- 2.5 msmoves shorter than this were at risk
- 0error reports: the position looked right
How we found it
One of our test benches has a logic analyzer on every step and direction line. It runs real CAM files and generated G-code around the clock, counts every step pulse the board sends, and compares the count with the position the board reports.
One morning a rotary file failed that check. Over a 176-line stretch, where each line moved X, Y and Z by tens of microns and the rotary axis by up to two degrees, the Z motor ended 20 steps (16 microns) away from where the board said it was. A rerun gave exactly the same numbers.
The first suspect was the measurement. But every direction change came at least 66 microseconds before the next step pulse, which is plenty for both the analyzer and a stepper driver. Then we read the firmware's own step counter with a debugger. It agreed with the motors, not with the report. The motors had stopped at the end of the second-to-last line. The board reported the last line as done.
Why the planner skipped the move
TinyG's planner has a minimum block time of 2.5 ms. A move it estimates will take less than that is refused, because a block that short cannot be planned properly. That refusal is meant to be harmless: the next move starts from the last planned position, so it covers the skipped distance as part of its own path. On a dense CAM file this happens all the time and nobody notices.
The trouble is the case with no next move. At the end of a job, or right before a dwell, a spindle stop, a G92 or a probe, the skipped distance is never covered. Meanwhile the board's G-code model has already moved on to the endpoint, the line was answered ok, and at rest the board reports the model's position. So every host showed the tool where the program said it should be.
ok.Why it went unnoticed for years
- The position report looked right. Nothing reported an error, and the displayed position matched the program.
- It depends on speed. The planner estimates a short move from the speed the machine is already moving at. Started from rest, the same move is estimated longer than 2.5 ms and runs. It took us four tries to reproduce it on purpose: our first attempts started from rest, or on an axis whose feed or jerk limit kept the move long enough.
- It is small. On a typical router, a few hundredths of a millimetre at the very end of a job.
It matters more than the size suggests in two cases. A G92 or G10 L20 issued at that point sets the work offset from a position the machine never reached, and every later job inherits the error. And a laser or plotter job made of many tiny segments at high speed is exactly where a final short move happens.
The fix
The planner still folds a refused move into the next one while there are more moves queued, so dense files run as fast as before. What changed is that the firmware now remembers a refused move, and runs it at the minimum block time when nothing else will cover it:
- when the queue has drained to the move that is running, since the machine is about to stop anyway;
- before a dwell or a queued command such as
M5orM2; - before
G28.3resets the position. A code review caught this one:G28.3rewrote the position before the queued command could act, so the remembered move would have been lost.
On the bench, the same sequence sent 2560 steps to the motor before the fix and 2581 after, where 2.0167 mm at 1280 steps/mm is 2581.4. Both cases are now regression tests that run on a real board before every merge.
Try it
The fix is merged into edge-next after the 450.03 release, in commit a3b4e6b3 (the fix itself is 456b4516). Update to the latest edge-next build to get it. See our edge-next post for what else changed and how to upgrade, and issue #301 for the details and the test.
However good the firmware gets, software is not an emergency stop. Every machine needs a hardware E-stop that cuts motor power, within reach of the operator.