Skip to content

Commit c50bcd5

Browse files
committed
G0/G1 blend guard, kink_vel fix, and tangential jerk budget
- Don't blend between rapid (G0) and feed (G1) moves to prevent unreachable junction velocities (matches planner 0/1 behavior). - Take min of per-joint Jacobian v_jerk_cap and INI-based aggregate kink_vel from createBlendSegment9, instead of unconditionally overwriting. Prevents high-override entry into blends. - Compute blend maxjerk from Jacobian-projected tangential jerk budget (BLEND_ACC_RATIO_TANGENTIAL * jlim[j] / proj[j]) instead of simple min(prev, tc). Accounts for non-trivial kinematics where joint projections differ from 1.0.
1 parent 7fe2b9c commit c50bcd5

1 file changed

Lines changed: 56 additions & 4 deletions

File tree

src/emc/motion_planning/motion_planning_9d_userspace.cc

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern "C" {
2929
#include "posemath.h"
3030
#include "blendmath.h" // pmCircleEffectiveMinRadius, findIntersectionAngle
3131
#include "atomic_9d.h" // atomicStoreDouble
32+
#include "motion_types.h" // EMC_MOTION_TYPE_TRAVERSE
3233
}
3334

3435
// External queue functions (from motion_planning_9d.cc - will be made public)
@@ -474,6 +475,13 @@ static int tpSetupBlend9D(TP_STRUCT *tp, TC_STRUCT *prev_tc, TC_STRUCT *tc)
474475
return 0;
475476
}
476477

478+
// Guard: don't blend between rapid (G0) and feed (G1) moves.
479+
// Velocity mismatch creates unreachable junction velocities.
480+
if ((prev_tc->canon_motion_type == EMC_MOTION_TYPE_TRAVERSE) ^
481+
(tc->canon_motion_type == EMC_MOTION_TYPE_TRAVERSE)) {
482+
return 0;
483+
}
484+
477485
// Guard: skip if either segment is too short for a meaningful blend
478486
// (e.g. near-zero-length move like "g1 x0 y0" when already at origin)
479487
if (prev_tc->target < 0.1 || tc->target < 0.1) {
@@ -670,8 +678,11 @@ static int tpSetupBlend9D(TP_STRUCT *tp, TC_STRUCT *prev_tc, TC_STRUCT *tc)
670678
v_plan = v_jerk_cap;
671679
blend_tc.maxvel = v_plan;
672680
}
673-
// Hard cap on blend exit (like kink_vel, ignores feed override)
674-
blend_tc.kink_vel = v_jerk_cap;
681+
// Hard cap on blend exit (like kink_vel, ignores feed override).
682+
// Take the min of the per-joint Jacobian cap (v_jerk_cap) and
683+
// the INI-based aggregate cap (set by createBlendSegment9).
684+
if (blend_tc.kink_vel <= 0 || v_jerk_cap < blend_tc.kink_vel)
685+
blend_tc.kink_vel = v_jerk_cap;
675686
// Hard cap on prev_tc exit → blend entry
676687
if (prev_tc->kink_vel <= 0 || v_jerk_cap < prev_tc->kink_vel)
677688
prev_tc->kink_vel = v_jerk_cap;
@@ -698,8 +709,49 @@ static int tpSetupBlend9D(TP_STRUCT *tp, TC_STRUCT *prev_tc, TC_STRUCT *tc)
698709
atomicStoreDouble(&blend_tc.shared_9d.final_vel, v_exit);
699710
atomicStoreDouble(&blend_tc.shared_9d.final_vel_limit, v_exit);
700711

701-
// Set jerk limit on blend from parent segments
702-
blend_tc.maxjerk = fmin(prev_tc->maxjerk, tc->maxjerk);
712+
// Set jerk limit on blend from per-joint tangential jerk budget.
713+
// The Pythagorean split BLEND_ACC_RATIO_TANGENTIAL (0.5) allocates
714+
// the tangential portion of each joint's jerk budget to Ruckig's
715+
// velocity transitions through the blend curve.
716+
{
717+
using motion_planning::g_userspace_kins_planner;
718+
double tangent_proj[9];
719+
tangent_proj[0] = fmax(fabs(solution.boundary.u_start_xyz.x),
720+
fabs(solution.boundary.u_end_xyz.x));
721+
tangent_proj[1] = fmax(fabs(solution.boundary.u_start_xyz.y),
722+
fabs(solution.boundary.u_end_xyz.y));
723+
tangent_proj[2] = fmax(fabs(solution.boundary.u_start_xyz.z),
724+
fabs(solution.boundary.u_end_xyz.z));
725+
tangent_proj[3] = fmax(fabs(solution.boundary.u_start_abc.x),
726+
fabs(solution.boundary.u_end_abc.x));
727+
tangent_proj[4] = fmax(fabs(solution.boundary.u_start_abc.y),
728+
fabs(solution.boundary.u_end_abc.y));
729+
tangent_proj[5] = fmax(fabs(solution.boundary.u_start_abc.z),
730+
fabs(solution.boundary.u_end_abc.z));
731+
tangent_proj[6] = fmax(fabs(solution.boundary.u_start_uvw.x),
732+
fabs(solution.boundary.u_end_uvw.x));
733+
tangent_proj[7] = fmax(fabs(solution.boundary.u_start_uvw.y),
734+
fabs(solution.boundary.u_end_uvw.y));
735+
tangent_proj[8] = fmax(fabs(solution.boundary.u_start_uvw.z),
736+
fabs(solution.boundary.u_end_uvw.z));
737+
738+
double tan_fraction = BLEND_ACC_RATIO_TANGENTIAL;
739+
double j_tan = 1e9;
740+
int nj = g_userspace_kins_planner.isEnabled()
741+
? g_userspace_kins_planner.getNumJoints() : 0;
742+
if (nj > 9) nj = 9;
743+
for (int j = 0; j < nj; j++) {
744+
if (tangent_proj[j] < 1e-6) continue;
745+
double jlim = g_userspace_kins_planner.getJointJerkLimit(j);
746+
if (jlim > 0 && jlim < 1e9) {
747+
double j_path = tan_fraction * jlim / tangent_proj[j];
748+
if (j_path < j_tan)
749+
j_tan = j_path;
750+
}
751+
}
752+
blend_tc.maxjerk = (j_tan < 1e8) ? j_tan
753+
: fmin(prev_tc->maxjerk, tc->maxjerk);
754+
}
703755

704756
// Enqueue blend segment
705757
TC_QUEUE_STRUCT *queue = &tp->queue;

0 commit comments

Comments
 (0)