CFLAGS += $(COMMON)
CFLAGS += -Wall -Werror # -Wno-error=unused-function
+CFLAGS += -Wno-error=strict-aliasing # for _invsqrt
CFLAGS += -gdwarf-2 -std=gnu99 -DF_CPU=$(CLOCK)UL -O3 -funroll-loops
CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums -funsigned-char
CFLAGS += -MD -MP -MT $@ -MF build/dep/$(@F).d
float delta_vmax; // max velocity difference for this move
float jerk; // maximum linear jerk term for this move
- float recip_jerk; // 1/Jm used for planning (computed & cached)
float cbrt_jerk; // cube root of Jm (computed & cached)
} mp_buffer_t;
float cruise_velocity;
float exit_velocity;
- float segments; // number of segments in line or arc
+ float segments; // number of segments in line
uint32_t segment_count; // count of running segments
- float segment_velocity; // computed velocity for aline segment
- float segment_time; // actual time increment per aline segment
+ float segment_velocity; // computed velocity for segment
+ float segment_time; // actual time increment per segment
forward_dif_t fdif; // forward difference levels
bool hold_planned; // true when a feedhold has been planned
- move_section_t section; // what section is the move in?
+ move_section_t section; // current move section
bool section_new; // true if it's a new section
} mp_exec_t;
// Compute next_segment velocity, velocity left to shed to brake to zero
float braking_velocity = _compute_next_segment_velocity();
// Distance to brake to zero from braking_velocity, bf is OK to use here
- float braking_length =
- mp_get_target_length(braking_velocity, 0, bf->recip_jerk);
+ float braking_length = mp_get_target_length(braking_velocity, 0, bf->jerk);
// Hack to prevent Case 2 moves for perfect-fit decels. Happens when homing.
if (available_length < braking_length && fp_ZERO(bf->exit_velocity))
float jerk = axes[axis].jerk_max * JERK_MULTIPLIER;
// Compute length to velocity given max jerk
- float length = mp_get_target_length(Vi, Vt, 1 / (jerk * JOG_JERK_MULT));
+ float length = mp_get_target_length(Vi, Vt, jerk * JOG_JERK_MULT);
// Compute move time
float move_time = 2 * length / (Vi + Vt);
/// Compute cached jerk terms used by planning
static void _calc_and_cache_jerk_values(mp_buffer_t *bf) {
static float jerk = 0;
- static float recip_jerk = 0;
static float cbrt_jerk = 0;
if (JERK_MATCH_PRECISION < fabs(bf->jerk - jerk)) { // Tolerance comparison
jerk = bf->jerk;
- recip_jerk = 1 / bf->jerk;
cbrt_jerk = cbrt(bf->jerk);
}
- bf->recip_jerk = recip_jerk;
bf->cbrt_jerk = cbrt_jerk;
}
// MIN_BODY_LENGTH
bf->body_length = 0;
float minimum_length =
- mp_get_target_length(bf->entry_velocity, bf->exit_velocity, bf->recip_jerk);
+ mp_get_target_length(bf->entry_velocity, bf->exit_velocity, bf->jerk);
// head-only & tail-only cases
if (bf->length <= (minimum_length + MIN_BODY_LENGTH)) {
// Set head and tail lengths for evaluating the next cases
bf->head_length =
- mp_get_target_length(bf->entry_velocity, bf->cruise_velocity,
- bf->recip_jerk);
+ mp_get_target_length(bf->entry_velocity, bf->cruise_velocity, bf->jerk);
bf->tail_length =
- mp_get_target_length(bf->exit_velocity, bf->cruise_velocity,
- bf->recip_jerk);
+ mp_get_target_length(bf->exit_velocity, bf->cruise_velocity, bf->jerk);
if (bf->head_length < MIN_HEAD_LENGTH) { bf->head_length = 0;}
if (bf->tail_length < MIN_TAIL_LENGTH) { bf->tail_length = 0;}
// initialize from previous iteration
bf->cruise_velocity = computed_velocity;
bf->head_length =
- mp_get_target_length(bf->entry_velocity, bf->cruise_velocity,
- bf->recip_jerk);
+ mp_get_target_length(bf->entry_velocity, bf->cruise_velocity, bf->jerk);
bf->tail_length =
- mp_get_target_length(bf->exit_velocity, bf->cruise_velocity,
- bf->recip_jerk);
+ mp_get_target_length(bf->exit_velocity, bf->cruise_velocity, bf->jerk);
if (bf->head_length > bf->tail_length) {
bf->head_length =
// set velocity and clean up any parts that are too short
bf->cruise_velocity = computed_velocity;
bf->head_length =
- mp_get_target_length(bf->entry_velocity, bf->cruise_velocity,
- bf->recip_jerk);
+ mp_get_target_length(bf->entry_velocity, bf->cruise_velocity, bf->jerk);
bf->tail_length = bf->length - bf->head_length;
if (bf->head_length < MIN_HEAD_LENGTH) {
* bl->cruise_vmax - used during forward planning to set cruise velocity
* bl->exit_vmax - used during forward planning to set exit velocity
* bl->delta_vmax - used during forward planning to set exit velocity
- * bl->recip_jerk - used during trapezoid generation
* bl->cbrt_jerk - used during trapezoid generation
*
* Variables that will be set during processing:
* [2] Cannot assume Vf >= Vi due to rounding errors and use of
* PLANNER_VELOCITY_TOLERANCE necessitating the introduction of fabs()
*/
-float mp_get_target_length(float Vi, float Vf, float recip_jerk) {
- return fabs(Vi - Vf) * sqrt(fabs(Vi - Vf) * recip_jerk);
+float mp_get_target_length(float Vi, float Vf, float jerk) {
+ return fabs(Vi - Vf) * invsqrt(jerk / fabs(Vi - Vf));
}
void mp_queue_push_nonstop(buffer_cb_t cb, uint32_t line);
-float mp_get_target_length(float Vi, float Vf, float recip_jerk);
+float mp_get_target_length(float Vi, float Vf, float jerk);
float mp_get_target_velocity(float Vi, float L, const mp_buffer_t *bf);
bool use_error = false;
if (!fp_ZERO(old_length_sqr)) {
- float new_time = time * sqrt(new_length_sqr / old_length_sqr);
+ float new_time = time * invsqrt(old_length_sqr / new_length_sqr);
if (EPSILON <= new_time && new_time <= MAX_SEGMENT_TIME) {
time = new_time;
square(a[AXIS_Z] - b[AXIS_Z]) + square(a[AXIS_A] - b[AXIS_A]) +
square(a[AXIS_B] - b[AXIS_B]) + square(a[AXIS_C] - b[AXIS_C]));
}
+
+
+/// Fast inverse square root originally from Quake III Arena code. Original
+/// comments left intact.
+/// See: https://en.wikipedia.org/wiki/Fast_inverse_square_root
+float invsqrt(float number) {
+ const float threehalfs = 1.5F;
+
+ float x2 = number * 0.5;
+ float y = number;
+ long i = *(long *)&y; // evil floating point bit level hacking
+ i = 0x5f3759df - (i >> 1); // what the fuck?
+ y = *(float *)&i;
+ y = y * (threehalfs - x2 * y * y); // 1st iteration
+ y = y * (threehalfs - x2 * y * y); // 2nd iteration, this can be removed
+
+ return y;
+}
inline float max4(float a, float b, float c, float d)
{return max(max(a, b), max(c, d));}
+float invsqrt(float number);
+
// Floating-point utilities
#define EPSILON 0.00001 // allowable rounding error for floats
inline bool fp_EQ(float a, float b) {return fabs(a - b) < EPSILON;}