TLDR; I think the speed matching algorithm in the motion planner should favor matching the extruding velocity if applicable, instead of the combined speed, to prevent over/under-extrusion on flow ratio change.
Dear RRF developers,
Recently I've been investigating bridging quality issues on my RRF Voron printer. The symptom is that the beginning or bridges are always heavily under-extruded to the point that half of the time it collapses for being too thin. I made a simple bridge STL trying to troubleshoot the issue:
This is designed to test the scenario where a perimeter enters bridge without turning. I tried to adjust target printing speed so that it maintains a constant volumetric flow rate, but the problem persists. The only way I could get acceptable bridges is to reduce bridge speed to very low value (< 15mm/s).
I believe the problem is due to the speed matching algorithm trying to match combined speed instead of extruding velocity, this caused instantaneous extruding velocity change that is impossible to compensate by pressure advance.
void DDA::MatchSpeeds() noexcept
{
for (size_t drive = 0; drive < MaxAxesPlusExtruders; ++drive)
{
if (directionVector[drive] != 0.0 || next->directionVector[drive] != 0.0)
{
const float totalFraction = fabsf(directionVector[drive] - next->directionVector[drive]);
const float jerk = totalFraction * beforePrepare.targetNextSpeed;
const float allowedJerk = reprap.GetPlatform().GetInstantDv(drive);
if (jerk > allowedJerk)
{
beforePrepare.targetNextSpeed = allowedJerk/totalFraction;
}
}
}
}
For example, let's say we have target perimeter speed of 60mm/s. Assuming 0.41mm extrusion width and 0.20mm layer height, the target flow rate would be 4.92mm^3/s. To maintain a constant volumetric rate, the bridge speed needs to be 39mm/s. Example:
M83
G0 X0
G1 X10 E3.409 F3600
G1 X20 E5.224 F2349
However, IIUC, constant flow rate is not going to happen with the current motion planner implementation, even if XY jerk limits permit it. The behavior is to pick the slower of the two as the target transition speed, then verify if the direction change is permitted by jerk limits. In this case, the transition speed would be F2349, thus causing a mismatch in extrusion velocity, which can't be compensated by pressure advance because it requires instantaneous position change.
This can be mitigated by setting an artificially low E jerk value, so that MatchSpeeds
returns a low transition speed. However that is not ideal because it basically causes such transition to always grind to a halt, and also limit acceleration to an extreme low value due to this in DDA::InitStandardMove
:
if (flags.xyMoving && nextMove.usePressureAdvance)
{
const float compensationTime = reprap.GetPlatform().GetPressureAdvance(LogicalDriveToExtruder(drive));
if (compensationTime > 0.0)
{
// Compensation causes instant velocity changes equal to acceleration * k, so we may need to limit the acceleration
accelerations[drive] = min<float>(accelerations[drive], reprap.GetPlatform().GetInstantDv(drive)/compensationTime);
}
}
I think this double usage of E jerk is a mistake. It makes no sense because not only it's being applied twice, but also it is applied in different spaces. In DDA::MatchSpeeds()
it is being applied to pre-pressure-advanced velocity, while in DDA::InitStandardMove
is being applied to pre-pressure-advanced acceleration, i.e. post-pressure-advanced velocity.
IMO the two usage of the E jerk values really should have used separate variable. Or for the sake of simplicity, I propose that the allowed E jerk during DDA::MatchSpeeds
really should have been 0, and we should allow the combined speed between the current move and the next move to mismatch, as long as jerk limit permits. In fact the behavior will be identical to current implementation when flow ratio remains constant, because matching extrusion velocity implies matching combined speed when flow ratio is constant.