Unaccelerated moves occur at max axial feedrate
Opened this issue · 1 comments
Unaccelerated moves such as the first move at (1) the start of a print with (2) an ill-defined position are done using the fastest max feedrate amongst the X, Y, and Z axes. It should be done at the minimum of { requested feedrate, max feedrate of the involved axes}.
What's happening is that get_longest_dda() is confused and returning the smallest of the step periods (microseconds/step) required to effect each of the maximum feedrates for the X, Y, and Z axes. It should be returning the largest of the step periods as that gives the slowest of the maximum feedrates.
Then, in queue_absolute_point() the code should see what the requested feedrate is in terms of steps per microsecond and then compare that to the value returned by a corrected get_longest_dda(). The larger of the two values should then be used in the resulting x3g output.
One possible fix:
static int queue_absolute_point(Gpx *gpx)
{
double distance, feedrate;
long longestDDA = gpx->longestDDA ? gpx->longestDDA : get_longest_dda(gpx);
Point5d steps = mm_to_steps(gpx, &gpx->target.position, &gpx->excess);
feedrate = gpx->current.feedrate;
if (feedrate > 0) {
// Seconds for the move is steps-needed / steps-per-mm / feedrate
// DDA is then 60 * 1000000 * seconds / steps-needed
// Thus DDA is 60 * 1000000 * steps-needed / (steps-per-mm * feedrate) / steps-needed
// DDA = 60 * 1000000 / (steps-per-mm * feedrate)
if (steps.x) {
long DDA = (long)(60.0 * 1000000.0 / (gpx->machine.x.steps_per_mm * feedrate));
if (DDA > longestDDA) longestDDA = DDA;
}
if (steps.y) {
long DDA = (long)(60.0 * 1000000.0 / (gpx->machine.y.steps_per_mm * feedrate));
if (DDA > longestDDA) longestDDA = DDA;
}
if (steps.z) {
long DDA = (long)(60.0 * 1000000.0 / (gpx->machine.z.steps_per_mm * feedrate));
if (DDA > longestDDA) longestDDA = DDA;
}
if (steps.a) {
long DDA = (long)(60.0 * 1000000.0 / (gpx->machine.a.steps_per_mm * feedrate));
if (DDA > longestDDA) longestDDA = DDA;
}
if (steps.b) {
long DDA = (long)(60.0 * 1000000.0 / (gpx->machine.b.steps_per_mm * feedrate));
if (DDA > longestDDA) longestDDA = DDA;
}
}
// Safety measure: don't send a DDA interval of 0 -- that's telling
// the bot to step as fast as it possibly can
if (longestDDA <= 0) longestDDA = 200;
begin_frame(gpx);
write_8(gpx, 139);
// int32: X coordinate, in steps
write_32(gpx, (int)steps.x);
// int32: Y coordinate, in steps
write_32(gpx, (int)steps.y);
// int32: Z coordinate, in steps
write_32(gpx, (int)steps.z);
// int32: A coordinate, in steps
write_32(gpx, -(int)steps.a);
// int32: B coordinate, in steps
write_32(gpx, -(int)steps.b);
// uint32: Feedrate, in microseconds between steps on the max delta. (DDA)
write_32(gpx, (int)longestDDA);
// reset current position
gpx->axis.positionKnown = gpx->axis.mask;
return end_frame(gpx);
}
and
static int get_longest_dda(Gpx *gpx)
{
// The DDA here is the microseconds/step. So a larger value is slower.
// We want the largest value, not the smallest value.
// calculate once
int longestDDA = gpx->longestDDA;
if(longestDDA == 0) {
longestDDA = (int)(60 * 1000000.0 / (gpx->machine.x.max_feedrate * gpx->machine.x.steps_per_mm));
int axisDDA = (int)(60 * 1000000.0 / (gpx->machine.y.max_feedrate * gpx->machine.y.steps_per_mm));
if(longestDDA > axisDDA) longestDDA = axisDDA;
axisDDA = (int)(60 * 1000000.0 / (gpx->machine.z.max_feedrate * gpx->machine.z.steps_per_mm));
if(longestDDA > axisDDA) longestDDA = axisDDA;
gpx->longestDDA = longestDDA;
}
return longestDDA;
}