Stock Anet A8 with FW updated to latest 2.0 bugfix.
If I send two "G1 X100 F6000" commands, one after the other, I see a brute acceleration since the end of the first movement...
Setting a really low travel acceleration (e.g. M204 T50) doesn't solve the huge acceleration at the start of the second movement (and it makes the issue pretty obvious).
Playing with (x in the example) jerk doesn't solve the issue.
Disabling Junction_deviation and/or Lin_advance doesn't solve the issue.
The issue seems occurring only when moving on the same direction.
If you send 2
G1 X100 F6000
The second command should be completely ignored, as the 2nd command is sending the printer to the exact position where it is right now...
Except he is in relative mode.
@MasterPIC — Do you see the same issue in absolute mode, using the following G-code?
G90
G1 X100 F6000
G1 X200 F6000
…where this is the same, but in relative mode…
G91
G1 X100 F6000
G1 X100 F6000
@thinkyhead
In absolute mode by sending the indicated commands it moves without any acceleration/deceleration around X=100 (so just a 200 length segment). I think it works as expected...
Sorry, I didn't report the bug correctly.
The issue occurs if I send the following code:
G91
G1 X100 F6000
G90
G91
G1 X100 F6000
So G90 and G91, one after the other, are the culprits...
I found the issue by Octoprint X keypad double press and I assumed the code sent was just a pair of G1 commands, one after the other, with nothing in the middle. But sending a pair of G1 commands by gcode file didn't show any issues. And giving a look at Octoprint terminal I found the G90 G91 commands added by Octoprint itself. Sorry for my mistake.
Same issue also with the following code:
G91
G1 X100 F6000
G90
G1 X200 F6000
I see a brute acceleration
Is the issue simply that the two moves are done separately instead of being chained together, or is it that the acceleration and top speed of the second move is unusually high?
The two moves are done separately and the acceleration of the second move is high, as if ramp is missing.
@MasterPIC — And this issue does not occur with earlier versions of Marlin (e.g., 1.1.8)?
The G90
/ G91
command is probably not relevant, but more that there is some additional time added between the moves. According to that theory, this code should produce the same result.
G90
G1 X100 F6000
M118 Hello World
G1 X200 F6000
@ejtagle — Can this be accounted for as a side-effect of the new planner behavior? In this case it sounds like the second move is being added after the point where the HOLD flag has expired. Whereas with the previous solution (splitting up the first move) the second move would have been added while the first (split) move was still executing, resulting in proper acceleration-chaining of the second move.
No, quite to the opposite: The block should start and end at 0 speed if it is not merged. I´ll try it ... just a sec...
I tried: The merging is perfect. There are 2 blocks in the queue, but check the acceleration/deceleration times:
get_current_block: Tail:0
Head:2
flag:2
extrude:0
step_event_count:8000
accelerate_until:167
decelerate_after:8000
cruise_rate:8000
acceleration_time:1723750
deceleration_time:0
acceleration_time_inverse:2491
deceleration_time_inverse:0
direction_bits:0
nominal_speed_sqr:10000.00
entry_speed_sqr:0.00
max_entry_speed_sqr:0.00
millimeters:100.00
acceleration:2400.00
nominal_rate:8000
initial_rate:120
final_rate:8000
acceleration_steps_per_s2:192000
segment_time_us:192000
get_current_block: Tail:1
Head:2
flag:2
extrude:0
step_event_count:8000
accelerate_until:0
decelerate_after:7834
cruise_rate:8000
acceleration_time:0
deceleration_time:1723750
acceleration_time_inverse:0
deceleration_time_inverse:2491
direction_bits:0
nominal_speed_sqr:10000.00
entry_speed_sqr:10000.00
max_entry_speed_sqr:10000.00
millimeters:100.00
acceleration:2400.00
nominal_rate:8000
initial_rate:8000
final_rate:120
acceleration_steps_per_s2:192000
segment_time_us:192000
The planner is working as expected
@ejtagle — Do you see any of unusual acceleration with this G-code…?
G91
G1 X100 F6000
G90
G1 X200 F6000
@thinkyhead I confirm the same issue with M118.
@thinkyhead : That was exactly the sequence i tried. There is an small difference, though... I am trying this in a 32bit board. Maybe AVR takes too much time and it is unable to do the merge... In such case, for AVR the coalescing timer should be increased...
@MasterPIC : Look inside planner.cpp, the line that says:
That is the time in milliseconds the planner will hold a block without executing it (ONLY when no other block is executing!) in hope the next one will arrive and then it will merge them. Maybe AVR is slow... Try increasing to 100 and see if that helps... 👍
@ejtagle BLOCK_DELAY_FOR_1ST_MOVE set at 100 solves the issue
Probably G90 - G91 swicthes won't appear often.
But I think M118 is generally often called to show useful info by LCD...
So, since LCD can be useful only when the user is next to the printer, what about adding an LCD timeout to disable LCD? Then the user could reactivate the LCD by a single press on one of the available keys...
I know that the LCD won't show current state, as soon as reactivated, but I think some users will prefer better prints and less info...
An LCD timeout set at 0 could disable this feature.
I think that managing a new timer is better than keeping LCD always on... What about this idea?
Obviously if you think that an appropriate BLOCK_DELAY_FOR_1ST_MOVE totally solves the issue then ignore my idea... 😄
There is already code implementing LCD throttle update, but it is not fast enough to react to the first move. Increasing that timer only delays by 1/10 of a second the first move, so should be harmless 👍
A default of 100 for BLOCK_DELAY_FOR_1ST_MOVE
should be harmless, if we want to do that.
@thinkyhead ... I know you want to restore the split in 2 first movement... Perhaps in this case could make a difference... But having 2 blocks instead of one can also cause trouble. All depends on how much CPU power is available...
The ISR will capture the first half of the move, thus freezing it. The 2nd half must be queued before that happens, otherwise you end up in exactly the same situation as @MasterPIC is describing, with a 2nd part that was not joined to the first - That was the purpose of the hold flag,...
As i told you at that point, i have no particular interest in any of both approachs, quite in fact, maybe they could complement each other...
Seems that with this solution (or splitting the first command) there is the possibility of the two commands not being joined if the timing is just right/wrong. But if they are not joined why do we get the sudden acceleration on the second one? Shouldn't the first segment go through the normal accelerate, cruise, decelerate followed by a repeat for the second, why the very high acceleration on the second line segment? Is there some sort of small window in which the planner thinks it has joined them, but the stepper sees them as separate? @ejtagle if you reduce the hold delay on your system can you reproduce the problem? Does this only happen when delivering commands by USB or can it also happen from an SD card?
But if they are not joined why do we get the sudden acceleration on the second one?
That's how it should work. Sounds like a regression issue to me, I fixed this with #9149. See the #9093 for details. The rewritten planner / stepper code might lack a simmilar "safety feature"?
@Sebastianv650, @gloomyandy : Gentlemen: There is an intented and unavoidable race condition between the planner and the stepper: The planner reverse pass goes from the head (last queued movement) to the tail (movement being executed right now), and then the forward pass does the opposite.
If, at the middle of the reverse pass the ISR consumes the tail movement, and get a new one, then the loop will probably use an already consumed block to plan, and will try to update the running block parameters.
The updating itself won´t be done, as there is a check for that in calculate_trapezoid_for_block
: Block must not be busy ... Also the isr checks that a block must not be flagged as "recalculate" (trapezoid). If it is, it holds its execution.
So, while the planner is planning, while doing the passes, there is a small window of time where a block is not "dirty" (=not flagged as "recalculate") and not busy, and it is considered as part of the blocks to be planned, but the ISR is able to pull it from the queue and execute it.
Let's consider the possible fixes:
Now, let's analyze when this problem could happen: Usually, the only way for this problem to happen is when the movement queue is empty or nearly empty - So, under normal printing conditions: NEVER.
It is just a cosmetic issue, all mitigations just make the general case usage much worse and risk causing stutter -
Of course, if someone else figures out a way that:
Then there is no problem implementing it 👍
Thanks for the explanation, it sounds like this is probably something not worth spending a lot of time on fixing.
I know you want to restore the split in 2 first movement
Well, only if it were to prove superior to holding the first block for a period of time.
The HOLD flag is fine with me, since it only ends up causing an extra delay in the case where a single move is sent without being followed by another within the BLOCK_DELAY_FOR_1ST_MOVE
period. As soon as a second move is added, the HOLD is immediately canceled and the first move is free to start, so in practice it should cause no additional or noticeable delay, and no more stuttering than would ordinarily exist due to other causes.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
A default of 100 for
BLOCK_DELAY_FOR_1ST_MOVE
should be harmless, if we want to do that.