Implement better machine speed limits checking. Do it for

each axis individually, as the combined speed of two or more
axes can be higher than the limit of a single one.

While this is tested to work well for all three acceleration
types, I'm not enthusiastic about the code, as it adds almost
500 bytes. Perhaps an efficient-coding-geek can help :-)
This commit is contained in:
Markus Hitter 2010-09-24 16:02:50 +02:00
parent d8e844bb67
commit 696baea16a
2 changed files with 27 additions and 11 deletions

30
dda.c
View File

@ -106,7 +106,7 @@ const uint8_t msbloc (uint32_t v) {
*/
void dda_create(DDA *dda, TARGET *target) {
uint32_t distance;
uint32_t distance, c_limit, c_limit_calc;
// initialise DDA to a known state
dda->allflags = 0;
@ -199,16 +199,37 @@ void dda_create(DDA *dda, TARGET *target) {
// distance * 2400 .. * F_CPU / 40000 so we can move a distance of up to 1800mm without overflowing
uint32_t move_duration = ((distance * 2400) / dda->total_steps) * (F_CPU / 40000);
// similarly, find out how fast we can run our axes.
// do this for each axis individually, as the combined speed of two or more axes can be higher than the capabilities of a single one.
c_limit = 0;
c_limit_calc = ((dda->x_delta * UM_PER_STEP_X * 2400) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_X) << 8;
if (c_limit_calc > c_limit)
c_limit = c_limit_calc;
c_limit_calc = ((dda->y_delta * UM_PER_STEP_Y * 2400) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_Y) << 8;
if (c_limit_calc > c_limit)
c_limit = c_limit_calc;
c_limit_calc = ((dda->z_delta * UM_PER_STEP_Z * 2400) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_Z) << 8;
if (c_limit_calc > c_limit)
c_limit = c_limit_calc;
c_limit_calc = ((dda->e_delta * UM_PER_STEP_E * 2400) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_E) << 8;
if (c_limit_calc > c_limit)
c_limit = c_limit_calc;
#ifdef ACCELERATION_REPRAP
// c is initial step time in IOclk ticks
dda->c = (move_duration / startpoint.F) << 8;
if (dda->c < c_limit)
dda->c = c_limit;
dda->end_c = (move_duration / target->F) << 8;
if (dda->end_c < c_limit)
dda->end_c = c_limit;
if (debug_flags & DEBUG_DDA) {
serial_writestr_P(PSTR(",md:")); serwrite_uint32(move_duration);
serial_writestr_P(PSTR(",c:")); serwrite_uint32(dda->c >> 8);
}
if (startpoint.F != target->F) {
if (dda->c != dda->end_c) {
uint32_t stF = startpoint.F / 4;
uint32_t enF = target->F / 4;
// now some constant acceleration stuff, courtesy of http://www.embedded.com/columns/technicalinsights/56800129?printable=true
@ -219,7 +240,6 @@ void dda_create(DDA *dda, TARGET *target) {
uint8_t msb_ssq = msbloc(ssq);
uint8_t msb_tot = msbloc(dda->total_steps);
dda->end_c = (move_duration / target->F) << 8;
// the raw equation WILL overflow at high step rates, but 64 bit math routines take waay too much space
// at 65536 mm/min (1092mm/s), ssq/esq overflows, and dsq is also close to overflowing if esq/ssq is small
// but if ssq-esq is small, ssq/dsq is only a few bits
@ -257,10 +277,14 @@ void dda_create(DDA *dda, TARGET *target) {
// c is initial step time in IOclk ticks
dda->c = ACCELERATION_STEEPNESS << 8;
dda->c_min = (move_duration / target->F) << 8;
if (dda->c_min < c_limit)
dda->c_min = c_limit;
dda->n = 1;
dda->ramp_state = RAMP_UP;
#else
dda->c = (move_duration / target->F) << 8;
if (dda->c < c_limit)
dda->c = c_limit;
#endif
}

View File

@ -393,14 +393,6 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
// G1 - synchronised motion
case 1:
// check speeds here
if (gcmd->seen_Z) {
if (gcmd->target.F > MAXIMUM_FEEDRATE_Z)
gcmd->target.F = MAXIMUM_FEEDRATE_Z;
}
else if (gcmd->target.F > MAXIMUM_FEEDRATE_X)
gcmd->target.F = MAXIMUM_FEEDRATE_X;
enqueue(&gcmd->target);
break;