208 namespace r = ::ranges;
209 namespace rv = ::ranges::views;
214 {
return simox::math::mat4f_to_xyyaw(pt.waypoint.pose.matrix()).z(); };
218 std::vector<double> orientations =
219 trajectory.points() | ranges::views::transform(toYaw) | ranges::to_vector;
224 const std::vector<double> inMovementDir = orientations;
227 const double startOrientation = orientations.front();
228 const double goalOrientation = orientations.back();
233 const std::size_t nOrientationStartGoalInfluence = std::ceil(
234 (orientations.size() - 1) * params.startGoalDistanceThreshold / trajectory.length());
237 const double signedAngleDiff =
angleDiff(goalOrientation, startOrientation);
241 const double signedAngleDiffDesired = [&]() ->
double
243 switch (params.predefinedRotationDirection)
247 if (signedAngleDiff <= 0)
249 return signedAngleDiff;
251 return -2 *
M_PI + signedAngleDiff;
255 if (signedAngleDiff >= 0)
257 return signedAngleDiff;
259 return 2 *
M_PI + signedAngleDiff;
262 return signedAngleDiff;
267 if (orientations.size() < 2 * nOrientationStartGoalInfluence)
271 const double angleIncrement = signedAngleDiffDesired / (orientations.size() - 1);
275 const std::vector<double> equidistantOrientations = [&]
277 std::vector<double> vec{orientations.front()};
278 for (std::size_t i = 1; i < orientations.size() - 1; i++)
280 vec.push_back(startOrientation + angleIncrement * i);
282 vec.push_back(orientations.back());
285 orientations = equidistantOrientations;
293 const double signedAngleDiff =
angleDiff(
294 inMovementDir.at(nOrientationStartGoalInfluence - 1), startOrientation);
296 const double angleIncrement = signedAngleDiff / (nOrientationStartGoalInfluence);
298 for (std::size_t i = 1; i < nOrientationStartGoalInfluence; i++)
300 orientations.at(i) = startOrientation + angleIncrement * i;
306 for (std::size_t i = nOrientationStartGoalInfluence;
307 i < orientations.size() - nOrientationStartGoalInfluence;
310 orientations.at(i) = inMovementDir.at(i);
316 const double signedAngleDiff =
angleDiff(
318 inMovementDir.at(orientations.size() - nOrientationStartGoalInfluence));
320 const double angleIncrement = signedAngleDiff / (nOrientationStartGoalInfluence);
322 for (std::size_t i = 1; i < nOrientationStartGoalInfluence; i++)
324 orientations.at(orientations.size() - nOrientationStartGoalInfluence + i) =
325 goalOrientation - angleIncrement * (nOrientationStartGoalInfluence - i);
332 for (
const auto& ori : orientations)
341 const float movementDirWeightStep =
342 (params.movementDirWeightEnd - params.movementDirWeightStart) / (params.iterations - 1);
349 const float movementDirWeight = params.movementDirWeightEnd;
374 for (std::size_t i = 1; i < orientations.size() - 1; i++)
376 const float walkingDirAlpha = 0.2;
378 const Eigen::Vector2f vMovementDir =
380 (Eigen::Rotation2Df(inMovementDir.at(i)) * Eigen::Vector2f::UnitX());
382 const Eigen::Vector2f vStartGoal =
383 (1.0 - walkingDirAlpha) *
384 (Eigen::Rotation2Df(orientations.at(i)) * Eigen::Vector2f::UnitX());
386 const Eigen::Vector2f vCombined = [&]() -> Eigen::Vector2f
388 if (movementDirWeight > 0)
390 return vMovementDir + vStartGoal;
411 const std::size_t nPoints = orientations.size();
413 ceres::Problem problem;
415 ARMARX_VERBOSE << orientations.size() - 2 <<
" orientations to optimize";
425 if (movementDirWeight > 0.F)
428 for (
size_t i = 1; i < (orientations.size() - 1); i++)
430 float actualMovementDirWeight = movementDirWeight;
436 actualMovementDirWeight *= i / 5.;
438 else if ((orientations.size() - i - 1) < 5)
440 actualMovementDirWeight *= (orientations.size() - i - 1) / 5.;
443 ceres::CostFunction* movementDirCostFunction =
445 actualMovementDirWeight);
447 ARMARX_DEBUG <<
"Adding OrientationPriorCostFunctor to optimize " << i;
448 problem.AddResidualBlock(
449 movementDirCostFunction,
nullptr, &orientations.at(i));
454 if (params.smoothnessWeight > 0.F)
457 for (
size_t i = 2; i < (orientations.size() - 2); i++)
459 ceres::CostFunction* smoothCostFunction =
462 ARMARX_DEBUG <<
"Addding SmoothOrientationCostFunctor to optimize " << i - 1
463 <<
", " << i <<
" and " << i + 1;
464 problem.AddResidualBlock(smoothCostFunction,
466 &orientations.at(i - 1),
468 &orientations.at(i + 1));
473 if (params.priorStartWeight > 0.F)
476 const auto connectedPointsInRangeStart =
477 trajectory.allConnectedPointsInRange(0, params.startGoalDistanceThreshold);
481 for (
const size_t i : connectedPointsInRangeStart)
484 if (i >= orientations.size() / 2)
490 inMovementDir.front(), params.priorStartWeight);
492 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor(start) to optimize "
494 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
499 if (params.priorEndWeight > 0.F)
503 const auto connectedPointsInRangeGoal = trajectory.allConnectedPointsInRange(
504 trajectory.poses().size() - 1, params.startGoalDistanceThreshold);
508 for (
const size_t i : connectedPointsInRangeGoal)
511 if (i < orientations.size() / 2)
517 inMovementDir.back(), params.priorEndWeight);
519 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor to optimize " << i;
520 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
526 if (params.smoothnessWeightStartGoal > 0.F and nPoints > 3)
530 ceres::CostFunction* smoothCostFunction =
532 params.smoothnessWeightStartGoal);
535 <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize 1 and 2";
536 problem.AddResidualBlock(
537 smoothCostFunction,
nullptr, &orientations.at(1), &orientations.at(2));
541 if (params.smoothnessWeightStartGoal > 0.F and nPoints > 3)
545 ceres::CostFunction* smoothCostFunction =
547 params.smoothnessWeightStartGoal);
549 ARMARX_DEBUG <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize "
550 << orientations.size() - 3 <<
" and " << orientations.size() - 2;
551 problem.AddResidualBlock(smoothCostFunction,
553 &orientations.at(orientations.size() - 3),
554 &orientations.at(orientations.size() - 2));
560 ceres::Solver::Options options;
561 options.linear_solver_type = ceres::DENSE_QR;
564 options.num_threads = 1;
565 options.minimizer_progress_to_stdout =
true;
566 options.max_num_iterations = 100;
567 options.function_tolerance = 0.01;
573 ceres::Solver::Summary summary;
574 Solve(options, &problem, &summary);
580 if (not summary.IsSolutionUsable())
591 orientations.front() = startOrientation;
592 orientations.back() = goalOrientation;
597 const std::vector<double> segmentLengths = [
this]
599 std::vector<double> lengths;
600 const auto& pts = trajectory.points();
601 lengths.reserve(pts.empty() ? 0 : pts.size() - 1);
603 for (std::size_t i = 0; i + 1 < pts.size(); i++)
605 lengths.push_back((pts.at(i + 1).waypoint.pose.translation() -
606 pts.at(i).waypoint.pose.translation())
613 smoothOrientations(orientations, segmentLengths, params.maxTurnRate);
616 for (
const auto& ori : orientations)
624 const float yaw = p.second;
627 Eigen::AngleAxisf(yaw, Eigen::Vector3f::UnitZ()).toRotationMatrix();
633 const auto modifiedTrajectory = rv::zip(trajectory.points(), orientations) |
634 rv::transform(applyOrientation) | r::to_vector;
637 .trajectory = modifiedTrajectory,