294 namespace r = ::ranges;
295 namespace rv = ::ranges::views;
300 {
return simox::math::mat4f_to_xyyaw(pt.waypoint.pose.matrix()).z(); };
304 std::vector<double> orientations =
305 trajectory.points() | ranges::views::transform(toYaw) | ranges::to_vector;
310 const std::vector<double> inMovementDir = orientations;
313 const double startOrientation = orientations.front();
314 const double goalOrientation = orientations.back();
319 const std::size_t nOrientationStartGoalInfluence = std::ceil(
320 (orientations.size() - 1) * params.startGoalDistanceThreshold / trajectory.length());
323 const double signedAngleDiff =
angleDiff(goalOrientation, startOrientation);
327 const double signedAngleDiffDesired = [&]() ->
double
329 switch (params.predefinedRotationDirection)
333 if (signedAngleDiff <= 0)
335 return signedAngleDiff;
337 return -2 *
M_PI + signedAngleDiff;
341 if (signedAngleDiff >= 0)
343 return signedAngleDiff;
345 return 2 *
M_PI + signedAngleDiff;
348 return signedAngleDiff;
353 if (orientations.size() < 2 * nOrientationStartGoalInfluence)
357 const double angleIncrement = signedAngleDiffDesired / (orientations.size() - 1);
361 const std::vector<double> equidistantOrientations = [&]
363 std::vector<double> vec{orientations.front()};
364 for (std::size_t i = 1; i < orientations.size() - 1; i++)
366 vec.push_back(startOrientation + angleIncrement * i);
368 vec.push_back(orientations.back());
371 orientations = equidistantOrientations;
379 const double signedAngleDiff =
angleDiff(
380 inMovementDir.at(nOrientationStartGoalInfluence - 1), startOrientation);
382 const double angleIncrement = signedAngleDiff / (nOrientationStartGoalInfluence);
384 for (std::size_t i = 1; i < nOrientationStartGoalInfluence; i++)
386 orientations.at(i) = startOrientation + angleIncrement * i;
392 for (std::size_t i = nOrientationStartGoalInfluence;
393 i < orientations.size() - nOrientationStartGoalInfluence;
396 orientations.at(i) = inMovementDir.at(i);
402 const double signedAngleDiff =
angleDiff(
404 inMovementDir.at(orientations.size() - nOrientationStartGoalInfluence));
406 const double angleIncrement = signedAngleDiff / (nOrientationStartGoalInfluence);
408 for (std::size_t i = 1; i < nOrientationStartGoalInfluence; i++)
410 orientations.at(orientations.size() - nOrientationStartGoalInfluence + i) =
411 goalOrientation - angleIncrement * (nOrientationStartGoalInfluence - i);
418 for (
const auto& ori : orientations)
427 const float movementDirWeightStep =
428 (params.movementDirWeightEnd - params.movementDirWeightStart) / (params.iterations - 1);
435 const float movementDirWeight = params.movementDirWeightEnd;
460 for (std::size_t i = 1; i < orientations.size() - 1; i++)
462 const float walkingDirAlpha = 0.2;
464 const Eigen::Vector2f vMovementDir =
466 (Eigen::Rotation2Df(inMovementDir.at(i)) * Eigen::Vector2f::UnitX());
468 const Eigen::Vector2f vStartGoal =
469 (1.0 - walkingDirAlpha) *
470 (Eigen::Rotation2Df(orientations.at(i)) * Eigen::Vector2f::UnitX());
472 const Eigen::Vector2f vCombined = [&]() -> Eigen::Vector2f
474 if (movementDirWeight > 0)
476 return vMovementDir + vStartGoal;
497 const std::size_t nPoints = orientations.size();
499 ceres::Problem problem;
501 ARMARX_VERBOSE << orientations.size() - 2 <<
" orientations to optimize";
511 if (movementDirWeight > 0.F)
514 for (
size_t i = 1; i < (orientations.size() - 1); i++)
516 float actualMovementDirWeight = movementDirWeight;
522 actualMovementDirWeight *= i / 5.;
524 else if ((orientations.size() - i - 1) < 5)
526 actualMovementDirWeight *= (orientations.size() - i - 1) / 5.;
529 ceres::CostFunction* movementDirCostFunction =
531 actualMovementDirWeight);
533 ARMARX_DEBUG <<
"Adding OrientationPriorCostFunctor to optimize " << i;
534 problem.AddResidualBlock(
535 movementDirCostFunction,
nullptr, &orientations.at(i));
540 if (params.smoothnessWeight > 0.F)
543 for (
size_t i = 2; i < (orientations.size() - 2); i++)
545 ceres::CostFunction* smoothCostFunction =
548 ARMARX_DEBUG <<
"Addding SmoothOrientationCostFunctor to optimize " << i - 1
549 <<
", " << i <<
" and " << i + 1;
550 problem.AddResidualBlock(smoothCostFunction,
552 &orientations.at(i - 1),
554 &orientations.at(i + 1));
559 if (params.priorStartWeight > 0.F)
562 const auto connectedPointsInRangeStart =
563 trajectory.allConnectedPointsInRange(0, params.startGoalDistanceThreshold);
567 for (
const size_t i : connectedPointsInRangeStart)
570 if (i >= orientations.size() / 2)
576 inMovementDir.front(), params.priorStartWeight);
578 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor(start) to optimize "
580 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
585 if (params.priorEndWeight > 0.F)
589 const auto connectedPointsInRangeGoal = trajectory.allConnectedPointsInRange(
590 trajectory.poses().size() - 1, params.startGoalDistanceThreshold);
594 for (
const size_t i : connectedPointsInRangeGoal)
597 if (i < orientations.size() / 2)
603 inMovementDir.back(), params.priorEndWeight);
605 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor to optimize " << i;
606 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
612 if (params.smoothnessWeightStartGoal > 0.F and nPoints > 3)
616 ceres::CostFunction* smoothCostFunction =
618 params.smoothnessWeightStartGoal);
621 <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize 1 and 2";
622 problem.AddResidualBlock(
623 smoothCostFunction,
nullptr, &orientations.at(1), &orientations.at(2));
627 if (params.smoothnessWeightStartGoal > 0.F and nPoints > 3)
631 ceres::CostFunction* smoothCostFunction =
633 params.smoothnessWeightStartGoal);
635 ARMARX_DEBUG <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize "
636 << orientations.size() - 3 <<
" and " << orientations.size() - 2;
637 problem.AddResidualBlock(smoothCostFunction,
639 &orientations.at(orientations.size() - 3),
640 &orientations.at(orientations.size() - 2));
646 ceres::Solver::Options options;
647 options.linear_solver_type = ceres::DENSE_QR;
650 options.num_threads = 1;
655 options.minimizer_progress_to_stdout =
657 options.max_num_iterations = 100;
658 options.function_tolerance = 0.01;
664 ceres::Solver::Summary summary;
665 Solve(options, &problem, &summary);
671 if (not summary.IsSolutionUsable())
682 orientations.front() = startOrientation;
683 orientations.back() = goalOrientation;
688 const std::vector<double> segmentLengths = [
this]
690 std::vector<double> lengths;
691 const auto& pts = trajectory.points();
692 lengths.reserve(pts.empty() ? 0 : pts.size() - 1);
694 for (std::size_t i = 0; i + 1 < pts.size(); i++)
696 lengths.push_back((pts.at(i + 1).waypoint.pose.translation() -
697 pts.at(i).waypoint.pose.translation())
704 smoothOrientations(orientations,
707 params.degenerateSegmentFraction * medianLength(segmentLengths));
710 for (
const auto& ori : orientations)
718 const float yaw = p.second;
721 Eigen::AngleAxisf(yaw, Eigen::Vector3f::UnitZ()).toRotationMatrix();
727 const auto modifiedTrajectory = rv::zip(trajectory.points(), orientations) |
728 rv::transform(applyOrientation) | r::to_vector;
731 .trajectory = modifiedTrajectory,