Skip to content

Commit a16f9b0

Browse files
committed
fix: TrajectoryBlenderTransitionWindow
- computes shift of the second_trajectory using average instead of max. (this shift may be exactly the sample_time of the second trajectory if uniform) - reduces sampling_time that approximates continuous time to 0.001 increasing the minimum distance between points to 1mm - ensures the addition of the first and the last points Tests: - adapts `checkBlendingJointSpaceContinuity` and `checkBlendingCartSpaceContinuity` acceleration computations to take into account different time samples among the trajectories - fixes occurrences of `joint_velocity_tolerance` and `joint_accleration_tolerance` in `checkBlendingJointSpaceContinuity` - adjust `checkBlendingCartSpaceContinuity` to return False in case of failed checks
1 parent 8271d56 commit a16f9b0

File tree

3 files changed

+73
-40
lines changed

3 files changed

+73
-40
lines changed

moveit_planners/pilz_industrial_motion_planner/src/trajectory_blender_transition_window.cpp

+24-15
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ bool pilz_industrial_motion_planner::TrajectoryBlenderTransitionWindow::blend(
136136

137137
// adjust the time from start of the first second trajectory point to ensure continuity of velocities (this implicitly
138138
// ensures continuity of accelerations)
139-
std::vector<double> time_offsets;
140139
auto second_start = res.second_trajectory->getFirstWayPointPtr();
141140
auto blend_end = res.blend_trajectory->getLastWayPointPtr();
142141

@@ -146,17 +145,22 @@ bool pilz_industrial_motion_planner::TrajectoryBlenderTransitionWindow::blend(
146145
std::vector<double> second_start_velocities;
147146
second_start->copyJointGroupVelocities(req.first_trajectory->getGroup()->getName(), second_start_velocities);
148147
double time_from_start = 0.0;
148+
std::size_t non_zero_velocity_count = 0;
149149
for (std::size_t i = 0; i < second_start_velocities.size(); ++i)
150150
{
151-
if (second_start_velocities[i] == 0)
151+
if (second_start_velocities[i] != 0)
152152
{
153-
continue;
153+
time_from_start += (second_start_positions[i] - blend_end_positions[i]) / second_start_velocities[i];
154+
++non_zero_velocity_count;
154155
}
155-
time_from_start = (second_start_positions[i] - blend_end_positions[i]) / second_start_velocities[i];
156-
time_offsets.push_back(time_from_start);
157156
}
158-
time_from_start = *std::max_element(time_offsets.begin(), time_offsets.end());
159-
res.second_trajectory->setWayPointDurationFromPrevious(0, time_from_start);
157+
if (non_zero_velocity_count > 0)
158+
{
159+
RCLCPP_INFO_STREAM(getLogger(),
160+
"Adjusting time from start of second trajectory to ensure velocity continuity. delta_time: "
161+
<< time_from_start / non_zero_velocity_count);
162+
res.second_trajectory->setWayPointDurationFromPrevious(0, time_from_start / non_zero_velocity_count);
163+
}
160164
res.error_code.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
161165
return true;
162166
}
@@ -303,17 +307,23 @@ void pilz_industrial_motion_planner::TrajectoryBlenderTransitionWindow::blendTra
303307
Eigen::Isometry3d blend_sample_pose;
304308

305309
// Define an arbitrary small sample time to sample the blending trajectory
306-
double sampling_time = 0.01;
310+
double sampling_time = 0.001;
307311

308312
int num_samples = std::floor(blend_duration / sampling_time);
309313
sampling_time = blend_duration / num_samples;
310314

311315
double blend_time = 0.0;
312316
Eigen::Isometry3d last_blend_sample_pose = blend_sample_pose1;
313-
while (blend_time <= blend_duration)
317+
318+
// Add the first point
319+
double time_offset = req.first_trajectory->getWayPointDurationFromPrevious(first_interse_index);
320+
waypoint.pose = tf2::toMsg(blend_sample_pose1);
321+
waypoint.time_from_start = rclcpp::Duration::from_seconds(time_offset);
322+
trajectory.points.push_back(waypoint);
323+
while (blend_time <= blend_duration + EPSILON)
314324
{
315325
// if the first trajectory does not reach the last sample, update
316-
if ((t_start + blend_time) < req.first_trajectory->getDuration())
326+
if ((t_start + blend_time) <= req.first_trajectory->getDuration())
317327
{
318328
blend_sample_pose1 = interpolatePose(req.first_trajectory, req.link_name, t_start + blend_time);
319329
}
@@ -338,20 +348,19 @@ void pilz_industrial_motion_planner::TrajectoryBlenderTransitionWindow::blendTra
338348

339349
blend_time += sampling_time;
340350
// Ensures samples are far enough apart to avoid numerical issues in numerical inverse kinematics
341-
if (((blend_sample_pose.translation() - last_blend_sample_pose.translation()).norm() < EPSILON) &&
342-
(blend_sample_pose.rotation().isApprox(last_blend_sample_pose.rotation(), 1e-3)))
351+
if (((blend_sample_pose.translation() - last_blend_sample_pose.translation()).norm() < 1e-3) &&
352+
(blend_sample_pose.rotation().isApprox(last_blend_sample_pose.rotation(), 1e-3)) &&
353+
(blend_time < blend_duration)) // Force the addition of the last point
343354
{
344355
continue;
345356
}
346357

347-
// std::cout << "blend_time: " << blend_time << std::endl;
348-
349358
// Store the last insert pose
350359
last_blend_sample_pose = blend_sample_pose;
351360

352361
// push to the trajectory
353362
waypoint.pose = tf2::toMsg(blend_sample_pose);
354-
waypoint.time_from_start = rclcpp::Duration::from_seconds(blend_time);
363+
waypoint.time_from_start = rclcpp::Duration::from_seconds(time_offset + blend_time);
355364
trajectory.points.push_back(waypoint);
356365
}
357366
}

moveit_planners/pilz_industrial_motion_planner/src/trajectory_functions.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ bool pilz_industrial_motion_planner::generateJointTrajectory(
362362
if (i == 0)
363363
{
364364
duration_current = trajectory.points.front().time_from_start.seconds();
365+
// This still assumes all the points in first_trajectory have the same duration
365366
duration_last = duration_current;
366367
}
367368
else

moveit_planners/pilz_industrial_motion_planner/test/test_utils.cpp

+48-25
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ bool testutils::toTCPPose(const moveit::core::RobotModelConstPtr& robot_model, c
560560

561561
bool testutils::checkOriginalTrajectoryAfterBlending(const pilz_industrial_motion_planner::TrajectoryBlendRequest& req,
562562
const pilz_industrial_motion_planner::TrajectoryBlendResponse& res,
563-
const double time_tolerance)
563+
const double /* time_tolerance */)
564564
{
565565
for (std::size_t i = 0; i < res.first_trajectory->getWayPointCount(); ++i)
566566
{
@@ -679,6 +679,7 @@ bool testutils::checkBlendingJointSpaceContinuity(const pilz_industrial_motion_p
679679

680680
// check the continuity between first trajectory and blend trajectory
681681
trajectory_msgs::msg::JointTrajectoryPoint first_end, blend_start;
682+
auto first_pend = first_traj.joint_trajectory.points[first_traj.joint_trajectory.points.size() - 2];
682683
first_end = first_traj.joint_trajectory.points.back();
683684
blend_start = blend_traj.joint_trajectory.points.front();
684685

@@ -709,13 +710,16 @@ bool testutils::checkBlendingJointSpaceContinuity(const pilz_industrial_motion_p
709710
return false;
710711
}
711712

712-
double blend_start_acc =
713-
(blend_start_velo - first_end.velocities.at(i)) / rclcpp::Duration(blend_start.time_from_start).seconds();
714-
if (fabs(blend_start_acc - blend_start.accelerations.at(i)) > joint_velocity_tolerance)
713+
double blend_start_acc = 2 * (blend_start_velo - first_end.velocities.at(i)) /
714+
(rclcpp::Duration(blend_start.time_from_start).seconds() +
715+
rclcpp::Duration(first_end.time_from_start).seconds() -
716+
rclcpp::Duration(first_pend.time_from_start).seconds());
717+
if (fabs(blend_start_acc - blend_start.accelerations.at(i)) > joint_accleration_tolerance)
715718
{
716719
std::cout << "Acceleration computed from positions/velocities are "
717720
"different from the value in trajectory."
718721
<< '\n'
722+
<< "position: " << blend_start.positions.at(i) << "; " << first_end.positions.at(i)
719723
<< "computed: " << blend_start_acc << "; "
720724
<< "in trajectory: " << blend_start.accelerations.at(i) << '\n';
721725
return false;
@@ -724,6 +728,7 @@ bool testutils::checkBlendingJointSpaceContinuity(const pilz_industrial_motion_p
724728

725729
// check the continuity between blend trajectory and second trajectory
726730
trajectory_msgs::msg::JointTrajectoryPoint blend_end, second_start;
731+
auto blend_pend = blend_traj.joint_trajectory.points[blend_traj.joint_trajectory.points.size() - 2];
727732
blend_end = blend_traj.joint_trajectory.points.back();
728733
second_start = second_traj.joint_trajectory.points.front();
729734

@@ -746,7 +751,7 @@ bool testutils::checkBlendingJointSpaceContinuity(const pilz_industrial_motion_p
746751
{
747752
double second_start_velo = (second_start.positions.at(i) - blend_end.positions.at(i)) /
748753
rclcpp::Duration(second_start.time_from_start).seconds();
749-
if (fabs(second_start_velo - second_start.velocities.at(i)) > joint_accleration_tolerance)
754+
if (fabs(second_start_velo - second_start.velocities.at(i)) > joint_velocity_tolerance)
750755
{
751756
std::cout << "Velocity computed from positions are different from the "
752757
"value in trajectory."
@@ -756,8 +761,10 @@ bool testutils::checkBlendingJointSpaceContinuity(const pilz_industrial_motion_p
756761
return false;
757762
}
758763

759-
double second_start_acc =
760-
(second_start_velo - blend_end.velocities.at(i)) / rclcpp::Duration(second_start.time_from_start).seconds();
764+
double second_start_acc = 2 * (second_start_velo - blend_end.velocities.at(i)) /
765+
(rclcpp::Duration(second_start.time_from_start).seconds() +
766+
rclcpp::Duration(blend_end.time_from_start).seconds() -
767+
rclcpp::Duration(blend_pend.time_from_start).seconds());
761768
if (fabs(second_start_acc - second_start.accelerations.at(i)) > joint_accleration_tolerance)
762769
{
763770
std::cout << "Acceleration computed from positions/velocities are "
@@ -843,9 +850,13 @@ bool testutils::checkBlendingCartSpaceContinuity(const pilz_industrial_motion_pl
843850

844851
// check the connection points between first trajectory and blend trajectory
845852
Eigen::Vector3d v_1, w_1, v_2, w_2, v_3, w_3;
846-
computeCartVelocity(pose_first_end_1, pose_first_end, duration, v_1, w_1);
847-
computeCartVelocity(pose_first_end, pose_blend_start, duration, v_2, w_2);
848-
computeCartVelocity(pose_blend_start, pose_blend_start_1, duration, v_3, w_3);
853+
double duration_first_end =
854+
res.first_trajectory->getWayPointDurationFromPrevious(res.first_trajectory->getWayPointCount() - 1);
855+
double duration_blend_start = res.blend_trajectory->getWayPointDurationFromPrevious(0);
856+
double duration_blend_start_1 = res.blend_trajectory->getWayPointDurationFromPrevious(1);
857+
computeCartVelocity(pose_first_end_1, pose_first_end, duration_first_end, v_1, w_1);
858+
computeCartVelocity(pose_first_end, pose_blend_start, duration_blend_start, v_2, w_2);
859+
computeCartVelocity(pose_blend_start, pose_blend_start_1, duration_blend_start_1, v_3, w_3);
849860

850861
// translational velocity
851862
if (v_2.norm() > max_trans_velo)
@@ -854,6 +865,7 @@ bool testutils::checkBlendingCartSpaceContinuity(const pilz_industrial_motion_pl
854865
"trajectory exceeds the limit."
855866
<< "Actual velocity (norm): " << v_2.norm() << "; "
856867
<< "Limits: " << max_trans_velo << '\n';
868+
return false;
857869
}
858870
// rotational velocity
859871
if (w_2.norm() > max_rot_velo)
@@ -862,65 +874,76 @@ bool testutils::checkBlendingCartSpaceContinuity(const pilz_industrial_motion_pl
862874
"trajectory exceeds the limit."
863875
<< "Actual velocity (norm): " << w_2.norm() << "; "
864876
<< "Limits: " << max_rot_velo << '\n';
877+
return false;
865878
}
866879
// translational acceleration
867-
Eigen::Vector3d a_1 = (v_2 - v_1) / duration;
868-
Eigen::Vector3d a_2 = (v_3 - v_2) / duration;
880+
Eigen::Vector3d a_1 = (v_2 - v_1) / duration_blend_start;
881+
Eigen::Vector3d a_2 = (v_3 - v_2) / duration_blend_start_1;
869882
if (a_1.norm() > max_trans_acc || a_2.norm() > max_trans_acc)
870883
{
871884
std::cout << "Translational acceleration between first trajectory and "
872885
"blend trajectory exceeds the limit."
873-
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_1.norm() << "; "
886+
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_2.norm() << "; "
874887
<< "Limits: " << max_trans_acc << '\n';
888+
return false;
875889
}
876890

877891
// rotational acceleration
878-
a_1 = (w_2 - w_1) / duration;
879-
a_2 = (w_3 - w_2) / duration;
892+
a_1 = (w_2 - w_1) / duration_blend_start;
893+
a_2 = (w_3 - w_2) / duration_blend_start_1;
880894
if (a_1.norm() > max_rot_acc || a_2.norm() > max_rot_acc)
881895
{
882896
std::cout << "Rotational acceleration between first trajectory and blend "
883897
"trajectory exceeds the limit."
884-
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_1.norm() << "; "
898+
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_2.norm() << "; "
885899
<< "Limits: " << max_rot_acc << '\n';
900+
return false;
886901
}
887902

888-
computeCartVelocity(pose_blend_end_1, pose_blend_end, duration, v_1, w_1);
889-
computeCartVelocity(pose_blend_end, pose_second_start, duration, v_2, w_2);
890-
computeCartVelocity(pose_second_start, pose_second_start_1, duration, v_3, w_3);
903+
double duration_blend_end =
904+
res.blend_trajectory->getWayPointDurationFromPrevious(res.blend_trajectory->getWayPointCount() - 1);
905+
double duration_second_start = res.second_trajectory->getWayPointDurationFromPrevious(0);
906+
double duration_second_start_1 = res.second_trajectory->getWayPointDurationFromPrevious(1);
907+
computeCartVelocity(pose_blend_end_1, pose_blend_end, duration_blend_end, v_1, w_1);
908+
computeCartVelocity(pose_blend_end, pose_second_start, duration_second_start, v_2, w_2);
909+
computeCartVelocity(pose_second_start, pose_second_start_1, duration_second_start_1, v_3, w_3);
891910

892911
if (v_2.norm() > max_trans_velo)
893912
{
894913
std::cout << "Translational velocity between blend trajectory and second "
895914
"trajectory exceeds the limit."
896915
<< "Actual velocity (norm): " << v_2.norm() << "; "
897916
<< "Limits: " << max_trans_velo << '\n';
917+
return false;
898918
}
899919
if (w_2.norm() > max_rot_velo)
900920
{
901921
std::cout << "Rotational velocity between blend trajectory and second "
902922
"trajectory exceeds the limit."
903923
<< "Actual velocity (norm): " << w_2.norm() << "; "
904924
<< "Limits: " << max_rot_velo << '\n';
925+
return false;
905926
}
906-
a_1 = (v_2 - v_1) / duration;
907-
a_2 = (v_3 - v_2) / duration;
927+
a_1 = (v_2 - v_1) / duration_second_start;
928+
a_2 = (v_3 - v_2) / duration_second_start_1;
908929
if (a_1.norm() > max_trans_acc || a_2.norm() > max_trans_acc)
909930
{
910931
std::cout << "Translational acceleration between blend trajectory and "
911932
"second trajectory exceeds the limit."
912-
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_1.norm() << "; "
933+
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_2.norm() << "; "
913934
<< "Limits: " << max_trans_acc << '\n';
935+
return false;
914936
}
915937
// check rotational acceleration
916-
a_1 = (w_2 - w_1) / duration;
917-
a_2 = (w_3 - w_2) / duration;
938+
a_1 = (w_2 - w_1) / duration_second_start;
939+
a_2 = (w_3 - w_2) / duration_second_start_1;
918940
if (a_1.norm() > max_rot_acc || a_2.norm() > max_rot_acc)
919941
{
920942
std::cout << "Rotational acceleration between blend trajectory and second "
921943
"trajectory exceeds the limit."
922-
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_1.norm() << "; "
944+
<< "Actual acceleration (norm): " << a_1.norm() << ", " << a_2.norm() << "; "
923945
<< "Limits: " << max_rot_acc << '\n';
946+
return false;
924947
}
925948

926949
return true;

0 commit comments

Comments
 (0)