293 namespace r = ::ranges;
294 namespace rv = ::ranges::views;
299 {
return simox::math::mat4f_to_xyyaw(pt.waypoint.pose.matrix()).z(); };
303 std::vector<double> orientations =
304 trajectory.points() | ranges::views::transform(toYaw) | ranges::to_vector;
309 const std::vector<double> inMovementDir = orientations;
312 const double startOrientation = orientations.front();
313 const double goalOrientation = orientations.back();
318 const std::size_t nOrientationStartGoalInfluence = std::ceil(
319 (orientations.size() - 1) * params.startGoalDistanceThreshold / trajectory.length());
322 const double signedAngleDiff =
angleDiff(goalOrientation, startOrientation);
326 const double signedAngleDiffDesired = [&]() ->
double
328 switch (params.predefinedRotationDirection)
332 if (signedAngleDiff <= 0)
334 return signedAngleDiff;
336 return -2 *
M_PI + signedAngleDiff;
340 if (signedAngleDiff >= 0)
342 return signedAngleDiff;
344 return 2 *
M_PI + signedAngleDiff;
347 return signedAngleDiff;
352 if (orientations.size() < 2 * nOrientationStartGoalInfluence)
356 const double angleIncrement = signedAngleDiffDesired / (orientations.size() - 1);
360 const std::vector<double> equidistantOrientations = [&]
362 std::vector<double> vec{orientations.front()};
363 for (std::size_t i = 1; i < orientations.size() - 1; i++)
365 vec.push_back(startOrientation + angleIncrement * i);
367 vec.push_back(orientations.back());
370 orientations = equidistantOrientations;
378 const double signedAngleDiff =
angleDiff(
379 inMovementDir.at(nOrientationStartGoalInfluence - 1), startOrientation);
381 const double angleIncrement = signedAngleDiff / (nOrientationStartGoalInfluence);
383 for (std::size_t i = 1; i < nOrientationStartGoalInfluence; i++)
385 orientations.at(i) = startOrientation + angleIncrement * i;
391 for (std::size_t i = nOrientationStartGoalInfluence;
392 i < orientations.size() - nOrientationStartGoalInfluence;
395 orientations.at(i) = inMovementDir.at(i);
401 const double signedAngleDiff =
angleDiff(
403 inMovementDir.at(orientations.size() - nOrientationStartGoalInfluence));
405 const double angleIncrement = signedAngleDiff / (nOrientationStartGoalInfluence);
407 for (std::size_t i = 1; i < nOrientationStartGoalInfluence; i++)
409 orientations.at(orientations.size() - nOrientationStartGoalInfluence + i) =
410 goalOrientation - angleIncrement * (nOrientationStartGoalInfluence - i);
417 for (
const auto& ori : orientations)
426 const float movementDirWeightStep =
427 (params.movementDirWeightEnd - params.movementDirWeightStart) / (params.iterations - 1);
434 const float movementDirWeight = params.movementDirWeightEnd;
459 for (std::size_t i = 1; i < orientations.size() - 1; i++)
461 const float walkingDirAlpha = 0.2;
463 const Eigen::Vector2f vMovementDir =
465 (Eigen::Rotation2Df(inMovementDir.at(i)) * Eigen::Vector2f::UnitX());
467 const Eigen::Vector2f vStartGoal =
468 (1.0 - walkingDirAlpha) *
469 (Eigen::Rotation2Df(orientations.at(i)) * Eigen::Vector2f::UnitX());
471 const Eigen::Vector2f vCombined = [&]() -> Eigen::Vector2f
473 if (movementDirWeight > 0)
475 return vMovementDir + vStartGoal;
496 const std::size_t nPoints = orientations.size();
498 ceres::Problem problem;
500 ARMARX_VERBOSE << orientations.size() - 2 <<
" orientations to optimize";
510 if (movementDirWeight > 0.F)
513 for (
size_t i = 1; i < (orientations.size() - 1); i++)
515 float actualMovementDirWeight = movementDirWeight;
521 actualMovementDirWeight *= i / 5.;
523 else if ((orientations.size() - i - 1) < 5)
525 actualMovementDirWeight *= (orientations.size() - i - 1) / 5.;
528 ceres::CostFunction* movementDirCostFunction =
530 actualMovementDirWeight);
532 ARMARX_DEBUG <<
"Adding OrientationPriorCostFunctor to optimize " << i;
533 problem.AddResidualBlock(
534 movementDirCostFunction,
nullptr, &orientations.at(i));
539 if (params.smoothnessWeight > 0.F)
542 for (
size_t i = 2; i < (orientations.size() - 2); i++)
544 ceres::CostFunction* smoothCostFunction =
547 ARMARX_DEBUG <<
"Addding SmoothOrientationCostFunctor to optimize " << i - 1
548 <<
", " << i <<
" and " << i + 1;
549 problem.AddResidualBlock(smoothCostFunction,
551 &orientations.at(i - 1),
553 &orientations.at(i + 1));
558 if (params.priorStartWeight > 0.F)
561 const auto connectedPointsInRangeStart =
562 trajectory.allConnectedPointsInRange(0, params.startGoalDistanceThreshold);
566 for (
const size_t i : connectedPointsInRangeStart)
569 if (i >= orientations.size() / 2)
575 inMovementDir.front(), params.priorStartWeight);
577 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor(start) to optimize "
579 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
584 if (params.priorEndWeight > 0.F)
588 const auto connectedPointsInRangeGoal = trajectory.allConnectedPointsInRange(
589 trajectory.poses().size() - 1, params.startGoalDistanceThreshold);
593 for (
const size_t i : connectedPointsInRangeGoal)
596 if (i < orientations.size() / 2)
602 inMovementDir.back(), params.priorEndWeight);
604 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor to optimize " << i;
605 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
611 if (params.smoothnessWeightStartGoal > 0.F and nPoints > 3)
615 ceres::CostFunction* smoothCostFunction =
617 params.smoothnessWeightStartGoal);
620 <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize 1 and 2";
621 problem.AddResidualBlock(
622 smoothCostFunction,
nullptr, &orientations.at(1), &orientations.at(2));
626 if (params.smoothnessWeightStartGoal > 0.F and nPoints > 3)
630 ceres::CostFunction* smoothCostFunction =
632 params.smoothnessWeightStartGoal);
634 ARMARX_DEBUG <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize "
635 << orientations.size() - 3 <<
" and " << orientations.size() - 2;
636 problem.AddResidualBlock(smoothCostFunction,
638 &orientations.at(orientations.size() - 3),
639 &orientations.at(orientations.size() - 2));
645 ceres::Solver::Options options;
646 options.linear_solver_type = ceres::DENSE_QR;
649 options.num_threads = 1;
650 options.minimizer_progress_to_stdout =
true;
651 options.max_num_iterations = 100;
652 options.function_tolerance = 0.01;
658 ceres::Solver::Summary summary;
659 Solve(options, &problem, &summary);
665 if (not summary.IsSolutionUsable())
676 orientations.front() = startOrientation;
677 orientations.back() = goalOrientation;
682 const std::vector<double> segmentLengths = [
this]
684 std::vector<double> lengths;
685 const auto& pts = trajectory.points();
686 lengths.reserve(pts.empty() ? 0 : pts.size() - 1);
688 for (std::size_t i = 0; i + 1 < pts.size(); i++)
690 lengths.push_back((pts.at(i + 1).waypoint.pose.translation() -
691 pts.at(i).waypoint.pose.translation())
698 smoothOrientations(orientations,
701 params.degenerateSegmentFraction * medianLength(segmentLengths));
704 for (
const auto& ori : orientations)
712 const float yaw = p.second;
715 Eigen::AngleAxisf(yaw, Eigen::Vector3f::UnitZ()).toRotationMatrix();
721 const auto modifiedTrajectory = rv::zip(trajectory.points(), orientations) |
722 rv::transform(applyOrientation) | r::to_vector;
725 .trajectory = modifiedTrajectory,