@@ -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