6 #include <SimoxUtility/math/convert/mat4f_to_xyyaw.h>
7 #include <SimoxUtility/math/convert/rpy_to_mat3f.h>
8 #include <SimoxUtility/math/periodic/periodic_clamp.h>
9 #include <SimoxUtility/math/periodic/periodic_diff.h>
10 #include <VirtualRobot/MathTools.h>
11 #include <VirtualRobot/Random.h>
21 #include <ceres/ceres.h>
22 #include <ceres/cost_function.h>
23 #include <ceres/jet.h>
24 #include <ceres/rotation.h>
25 #include <ceres/sized_cost_function.h>
26 #include <range/v3/range/conversion.hpp>
27 #include <range/v3/view/drop.hpp>
28 #include <range/v3/view/drop_last.hpp>
29 #include <range/v3/view/transform.hpp>
30 #include <range/v3/view/zip.hpp>
36 trajectory(trajectory), params(params)
43 namespace r = ::ranges;
44 namespace rv = ::ranges::views;
47 {
return simox::math::mat4f_to_xyyaw(pt.waypoint.pose.matrix()).z(); };
51 std::vector<double> orientations =
57 const std::vector<double> inMovementDir = orientations;
60 const double& startOrientation = orientations.front();
61 const double& goalOrientation = orientations.back();
62 const double signedAngleDiff =
63 std::fmod<double>(goalOrientation - startOrientation + 3 *
M_PI, 2 *
M_PI) -
M_PI;
64 const double signedAngleDiffDesired = [&]() ->
double
71 if (signedAngleDiff <= 0)
73 return signedAngleDiff;
75 return -2 *
M_PI + signedAngleDiff;
78 if (signedAngleDiff >= 0)
80 return signedAngleDiff;
82 return 2 *
M_PI + signedAngleDiff;
85 return signedAngleDiff;
87 const double angleIncrement = signedAngleDiffDesired / (orientations.size() - 1);
91 const std::vector<double> equidistantOrientations = [&]
93 std::vector<double> vec{orientations.front()};
94 for (std::size_t i = 1; i < orientations.size() - 1; i++)
96 vec.push_back(startOrientation + angleIncrement * i);
98 vec.push_back(orientations.back());
101 orientations = equidistantOrientations;
107 const float movementDirWeightStep =
113 for (
int it = 0; it < params.
iterations; it++)
115 const float movementDirWeight =
121 for (std::size_t i = 1; i < orientations.size() - 1; i++)
123 const float walkingDirAlpha = 0.2;
125 const Eigen::Vector2f vMovementDir =
127 (Eigen::Rotation2Df(inMovementDir.at(i)) * Eigen::Vector2f::UnitX());
129 const Eigen::Vector2f vStartGoal =
130 (1.0 - walkingDirAlpha) *
131 (Eigen::Rotation2Df(orientations.at(i)) * Eigen::Vector2f::UnitX());
133 const Eigen::Vector2f vCombined = [&]() -> Eigen::Vector2f
135 if (movementDirWeight > 0)
137 return vMovementDir + vStartGoal;
142 orientations.at(i) = std::atan2(vCombined.y(), vCombined.x());
149 const std::size_t nPoints = orientations.size();
151 ceres::Problem problem;
153 ARMARX_VERBOSE << orientations.size() - 2 <<
" orientations to optimize";
164 if (movementDirWeight > 0.
F)
167 for (
size_t i = 1; i < (orientations.size() - 1); i++)
169 float actualMovementDirWeight = movementDirWeight;
175 actualMovementDirWeight *= i / 5.;
177 else if ((orientations.size() - i - 1) < 5)
179 actualMovementDirWeight *= (orientations.size() - i - 1) / 5.;
183 inMovementDir.at(i), actualMovementDirWeight);
185 ARMARX_DEBUG <<
"Adding OrientationPriorCostFunctor to optimize " << i;
186 problem.AddResidualBlock(movementDirCostFunction,
nullptr, &orientations.at(i));
194 for (
size_t i = 2; i < (orientations.size() - 2); i++)
196 ceres::CostFunction* smoothCostFunction =
199 ARMARX_DEBUG <<
"Addding SmoothOrientationCostFunctor to optimize " << i - 1
200 <<
", " << i <<
" and " << i + 1;
201 problem.AddResidualBlock(smoothCostFunction,
203 &orientations.at(i - 1),
205 &orientations.at(i + 1));
213 const auto connectedPointsInRangeStart =
216 for (
const size_t i : connectedPointsInRangeStart)
219 if (i >= orientations.size() / 2)
227 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor(start) to optimize " << i;
228 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
240 for (
const size_t i : connectedPointsInRangeGoal)
243 if (i < orientations.size() / 2)
251 ARMARX_DEBUG <<
"Addding OrientationPriorCostFunctor to optimize " << i;
252 problem.AddResidualBlock(priorCostFunction,
nullptr, &orientations.at(i));
265 ARMARX_DEBUG <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize 1 and 2";
266 problem.AddResidualBlock(
267 smoothCostFunction,
nullptr, &orientations.at(1), &orientations.at(2));
278 ARMARX_DEBUG <<
"Addding SmoothOrientationFixedPreCostFunctor to optimize "
279 << orientations.size() - 3 <<
" and " << orientations.size() - 2;
280 problem.AddResidualBlock(smoothCostFunction,
282 &orientations.at(orientations.size() - 3),
283 &orientations.at(orientations.size() - 2));
290 ceres::Solver::Options options;
291 options.linear_solver_type = ceres::DENSE_QR;
292 options.minimizer_progress_to_stdout =
false;
293 options.max_num_iterations = 100;
294 options.function_tolerance = 0.01;
300 ceres::Solver::Summary summary;
301 Solve(options, &problem, &summary);
305 const auto clampInPlace = [](
auto& val)
306 { val = simox::math::periodic_clamp(val, -
M_PI,
M_PI); };
308 std::for_each(orientations.begin(), orientations.end(), clampInPlace);
310 if (not summary.IsSolutionUsable())
320 const float yaw = p.second;
322 tp.
waypoint.
pose.linear() = simox::math::rpy_to_mat3f(0.
F, 0.
F, yaw);
328 const auto modifiedTrajectory = rv::zip(trajectory.
points(), orientations) |