@@ -363,6 +363,93 @@ void JointSaturationLimiter<trajectory_msgs::msg::JointTrajectoryPoint>::clamp_j
363363 (current_joint_velocities[index] * dt_seconds) +
364364 (0.5 * desired_acc_[index] * dt_seconds * dt_seconds);
365365 }
366+
367+ // Post-jerk re-check: jerk-limited acceleration may cause velocity or
368+ // acceleration/deceleration to exceed their limits because jerk pulls
369+ // acceleration toward current_acc, which may itself exceed limits or
370+ // cause velocity to overshoot.
371+
372+ // Re-check velocity
373+ if (joint_limits_[index].has_velocity_limits )
374+ {
375+ if (std::fabs (desired_vel_[index]) > joint_limits_[index].max_velocity )
376+ {
377+ desired_vel_[index] =
378+ std::copysign (joint_limits_[index].max_velocity , desired_vel_[index]);
379+ vel_limit_hit_[index] = true ;
380+ limits_enforced = true ;
381+
382+ desired_acc_[index] =
383+ (desired_vel_[index] - current_joint_velocities[index]) / dt_seconds;
384+
385+ if (has_desired_position)
386+ {
387+ desired_pos_[index] =
388+ current_joint_states.positions [index] + desired_vel_[index] * dt_seconds;
389+ }
390+ }
391+ }
392+
393+ // Re-check acceleration and deceleration
394+ if (
395+ joint_limits_[index].has_acceleration_limits ||
396+ joint_limits_[index].has_deceleration_limits )
397+ {
398+ if (
399+ std::fabs (desired_acc_[index]) <= VALUE_CONSIDERED_ZERO ||
400+ std::isnan (desired_acc_[index]))
401+ {
402+ desired_acc_[index] =
403+ (desired_vel_[index] - current_joint_velocities[index]) / dt_seconds;
404+ }
405+
406+ bool deceleration_limit_applied = false ;
407+ bool limit_applied = false ;
408+ auto apply_recheck_limit =
409+ [&](const double limit, std::vector<double > & vec, std::vector<bool > & hit_flag) -> bool
410+ {
411+ if (std::fabs (vec[index]) > limit)
412+ {
413+ vec[index] = std::copysign (limit, vec[index]);
414+ hit_flag[index] = true ;
415+ limits_enforced = true ;
416+ return true ;
417+ }
418+ return false ;
419+ };
420+
421+ // Check deceleration (velocity changing toward zero)
422+ if (
423+ (desired_acc_[index] < 0 && current_joint_velocities[index] > 0 ) ||
424+ (desired_acc_[index] > 0 && current_joint_velocities[index] < 0 ))
425+ {
426+ if (joint_limits_[index].has_deceleration_limits )
427+ {
428+ limit_applied = apply_recheck_limit (
429+ joint_limits_[index].max_deceleration , desired_acc_, dec_limit_hit_);
430+ deceleration_limit_applied = true ;
431+ }
432+ }
433+
434+ // Check acceleration (fallback to acceleration if no decel check applied)
435+ if (joint_limits_[index].has_acceleration_limits && !deceleration_limit_applied)
436+ {
437+ limit_applied = apply_recheck_limit (
438+ joint_limits_[index].max_acceleration , desired_acc_, acc_limit_hit_);
439+ }
440+
441+ if (limit_applied)
442+ {
443+ desired_vel_[index] =
444+ current_joint_velocities[index] + desired_acc_[index] * dt_seconds;
445+ if (has_desired_position)
446+ {
447+ desired_pos_[index] = current_joint_states.positions [index] +
448+ current_joint_velocities[index] * dt_seconds +
449+ 0.5 * desired_acc_[index] * dt_seconds * dt_seconds;
450+ }
451+ }
452+ }
366453 }
367454 }
368455
0 commit comments