whpthomas/GPX

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;

}