10 #include <Eigen/Geometry>
12 #include <SimoxUtility/shapes/CircleBase.h>
13 #include <VirtualRobot/MathTools.h>
14 #include <VirtualRobot/math/Helpers.h>
15 #include <VirtualRobot/math/LinearInterpolatedPose.h>
25 #include <range/v3/action/insert.hpp>
26 #include <range/v3/algorithm/none_of.hpp>
27 #include <range/v3/numeric/accumulate.hpp>
28 #include <range/v3/range/conversion.hpp>
29 #include <range/v3/view/all.hpp>
30 #include <range/v3/view/concat.hpp>
31 #include <range/v3/view/for_each.hpp>
32 #include <range/v3/view/group_by.hpp>
33 #include <range/v3/view/reverse.hpp>
34 #include <range/v3/view/sliding.hpp>
35 #include <range/v3/view/transform.hpp>
36 #include <range/v3/view/zip.hpp>
63 .end = segment.
end - circle.center()};
65 const float d_r = localSegment.d().norm();
66 const float D = localSegment.start.x() * localSegment.end.y() - localSegment.end.x() -
67 localSegment.start.y();
70 static_cast<float>(std::pow(circle.radius(), 2) * std::pow(d_r, 2) - std::pow(D, 2));
86 std::vector<Eigen::Vector2f>
91 .end = segment.
end - circle.center()};
93 const float d_r = localSegment.d().norm();
94 const float D = localSegment.start.x() * localSegment.end.y() - localSegment.end.x() -
95 localSegment.start.y();
98 static_cast<float>(std::pow(circle.radius(), 2) * std::pow(d_r, 2) - std::pow(D, 2));
102 return std::vector<Eigen::Vector2f>{};
109 std::vector<Eigen::Vector2f>
v;
110 v.emplace_back(D * localSegment.d().y() / std::pow(d_r, 2) + circle.center().x(),
111 -D * localSegment.d().x() / std::pow(d_r, 2) + circle.center().y());
118 std::copysign(localSegment.d().y(), localSegment.d().x()) *
std::sqrt(delta);
119 const float hy = std::fabs(localSegment.d().y()) *
std::sqrt(delta);
121 std::vector<Eigen::Vector2f>
v;
122 v.emplace_back((D * localSegment.d().y() + hx) / std::pow(d_r, 2) + circle.center().x(),
123 (-D * localSegment.d().x() + hy) / std::pow(d_r, 2) + circle.center().y());
124 v.emplace_back((D * localSegment.d().y() - hx) / std::pow(d_r, 2) + circle.center().x(),
125 (-D * localSegment.d().x() - hy) / std::pow(d_r, 2) + circle.center().y());
149 trajectoryPoints.reserve(path.size());
153 std::back_inserter(trajectoryPoints),
154 [&](
const auto& p) { return toTrajectoryPoint(p, velocity); });
156 return trajectoryPoints;
165 trajectoryPoints.reserve(path.size());
167 const auto convert = [](
const auto& p)
169 const auto& [pose, velocity] = p;
179 GlobalTrajectory::InternalProjection
180 GlobalTrajectory::projectInternal(
const Position& point,
185 InternalProjection bestProj;
187 for (
size_t i = 0; i < pts.size() - 1; i++)
189 const auto& wpBefore = pts.at(i);
190 const auto& wpAfter = pts.at(i + 1);
202 const auto closestPoint = VirtualRobot::MathTools::nearestPointOnSegment<Position>(
203 wpBefore.waypoint.pose.translation(), wpAfter.waypoint.pose.translation(), point);
205 const float currentDistance = (closestPoint - point).
norm();
210 const float d1 = (closestPoint - wpBefore.waypoint.pose.translation()).
norm();
212 (wpBefore.waypoint.pose.translation() - wpAfter.waypoint.pose.translation())
216 const float t = d1 / d;
218 math::LinearInterpolatedPose ip(
219 wpBefore.waypoint.pose.matrix(), wpAfter.waypoint.pose.matrix(), 0, 1,
true);
221 bestProj.indexBefore = i;
222 bestProj.projection.waypoint.pose = ip.Get(t);
224 switch (velocityInterpolation)
227 bestProj.projection.velocity =
228 wpBefore.velocity + (wpAfter.velocity - wpBefore.velocity) * t;
231 bestProj.projection.velocity = wpBefore.velocity;
251 .wayPointBefore = pts.front(),
252 .wayPointAfter = pts.front(),
256 InternalProjection intProj = projectInternal(point, velocityInterpolation);
258 const auto& wpBefore = pts.at(intProj.indexBefore);
259 const auto& wpAfter = pts.at(intProj.indexBefore + 1);
270 if (intProj.indexBefore == (pts.size() - 2))
275 if (intProj.indexBefore == 0)
286 std::pair<GlobalTrajectory, bool>
289 const InternalProjection intProj =
297 for (
size_t i = intProj.indexBefore + 1; i < pts.size(); i++)
299 const auto& nextWp = pts.at(i);
301 const float segmentDistance =
302 (nextWp.waypoint.pose.translation() - lastWp.
waypoint.
pose.translation()).
norm();
304 if (segmentDistance < remainingDistance)
306 subTraj.mutablePoints().push_back(nextWp);
308 remainingDistance -= segmentDistance;
313 const float t = remainingDistance / segmentDistance;
315 math::LinearInterpolatedPose ip(
316 lastWp.
waypoint.
pose.matrix(), nextWp.waypoint.pose.matrix(), 0, 1,
true);
317 const float velocity = lastWp.
velocity + (nextWp.velocity - lastWp.
velocity) * t;
319 subTraj.mutablePoints().push_back({{
static_cast<Pose>(ip.Get(t))}, velocity});
321 return {subTraj,
false};
326 return {subTraj,
true};
329 std::vector<Eigen::Vector3f>
333 {
return wp.waypoint.pose.translation(); };
346 std::vector<Pose>
poses;
347 poses.reserve(pts.size());
351 std::back_inserter(
poses),
353 { return pt.waypoint.pose; });
374 const float velocity)
379 path.reserve(waypoints.size());
381 if (waypoints.empty())
383 return FromPath({start, goal}, velocity);
386 path.push_back(start);
395 const Eigen::Rotation2Df pose_R_robot =
396 Eigen::Rotation2Df(yaw) * Eigen::Rotation2Df(-M_PI_2f32);
409 waypoints | ranges::views::sliding(2) |
411 [&directedPose](
const auto& p) ->
Pose
413 const auto& [position, _] = p;
414 const auto target = position + 1;
416 return directedPose(*position, *target);
419 path.emplace_back(directedPose(waypoints.back(), goal.translation()));
420 path.push_back(goal);
429 const std::vector<float>& velocity)
435 path.reserve(waypoints.size());
437 if (waypoints.empty())
439 return FromPath({start, goal}, velocity);
442 path.push_back(start);
451 const Eigen::Rotation2Df pose_R_robot =
452 Eigen::Rotation2Df(yaw) * Eigen::Rotation2Df(-M_PI_2f32);
465 waypoints | ranges::views::sliding(2) |
467 [&directedPose](
const auto& p) ->
Pose
469 const auto& [position, _] = p;
470 const auto target = position + 1;
472 return directedPose(*position, *target);
475 path.emplace_back(directedPose(waypoints.back(), goal.translation()));
476 path.push_back(goal);
487 {
return wp.waypoint.pose; };
494 Position pointOnPath = originalPath.front().translation();
496 for (
const auto& wp : originalPath | ranges::views::sliding(2))
498 const auto& [wp1, _] = wp;
499 const auto wp2 = wp1 + 1;
515 pointOnPath += dir * eps;
516 resampledPath.push_back(pointOnPath);
522 const float distanceEnd =
524 if (distanceEnd < eps)
536 if (not(isect.size() == 2))
542 for (
const auto& pt : isect)
549 const auto d0 = (isect.at(0) - lineSegment.start).normalized();
552 const auto d = (lineSegment.end - lineSegment.start).normalized();
565 resampledPath.push_back(pointOnPath);
577 return resampledPath;
595 if (resampledPathForward.empty() or resampledPathBackward.empty())
597 ARMARX_DEBUG <<
"The resampled path contains no points. This means that it is likely "
601 pts.front().waypoint.pose, resampledPathForward, pts.back().waypoint.pose, 0.F);
604 <<
"The resampled trajectory is only allowed to contains no points if it is "
611 ARMARX_DEBUG <<
"Resampled path forward contains " << resampledPathForward.size()
613 ARMARX_DEBUG <<
"Resampled path backwards contains " << resampledPathBackward.size()
627 for (
const auto& [wpForward, wpBackward] :
628 ranges::views::zip(resampledPathForward, resampledPathBackward))
630 segmentForward.push_back(wpForward);
631 if ((pivot - wpForward).
norm() < eps)
637 segmentBackward.push_back(wpBackward);
638 if ((pivot - wpBackward).
norm() < eps)
651 pts.front().waypoint.pose, resampledPath, pts.back().waypoint.pose, 0.F);
657 const auto projection =
getProjection(pt.waypoint.pose.translation(),
659 pt.velocity = projection.projection.velocity;
662 std::for_each(resampledTrajectory.mutablePoints().begin(),
663 resampledTrajectory.mutablePoints().end(),
678 return resampledTrajectory;
684 namespace r = ::ranges;
686 const auto distanceBetweenWaypoints = [](
const auto& p) ->
float
688 const auto& [p1, _] = p;
689 const auto p2 = p1 + 1;
690 return (p1->waypoint.pose.translation() - p2->waypoint.pose.translation()).
norm();
695 const float length = r::accumulate(rng, 0.
F);
707 std::for_each(pts.begin(),
710 { pt.velocity = std::clamp(pt.velocity, -maxVelocity, maxVelocity); });
716 namespace r = ::ranges;
718 const auto distanceBetweenWaypoints = [](
const auto& p) ->
float
720 const auto& [p1, _] = p;
721 const auto p2 = p1 + 1;
722 return (p1->waypoint.pose.translation() - p2->waypoint.pose.translation()).
norm();
727 return ranges::none_of(
728 rng, [&maxDistance](
const auto& dist) ->
bool {
return dist > maxDistance; });
731 const std::vector<GlobalTrajectoryPoint>&
737 std::vector<GlobalTrajectoryPoint>&
749 for (
int i = 0; i < static_cast<int>(pts.size() - 1); i++)
751 const auto& start = pts.at(i);
752 const auto& goal = pts.at(i + 1);
755 (goal.waypoint.pose.translation() - start.waypoint.pose.translation()).
norm();
757 const float startVelocity = start.velocity;
758 const float goalVelocity = goal.velocity;
760 constexpr
int nSamples = 100;
762 for (
int j = 0; j < nSamples; j++)
764 const float progress =
static_cast<float>(j) / nSamples;
766 const float v = startVelocity + progress * (goalVelocity - startVelocity);
769 const float t =
s /
v;
782 {
return std::isfinite(pt.velocity) and pt.velocity < 3000; };
784 return std::all_of(pts.begin(), pts.end(),
isValid);
790 const core::Position referencePosition = pts.at(idx).waypoint.pose.translation();
792 const auto isInRange = [&](
const std::size_t i) ->
bool
794 const float posDiff =
795 (pts.at(i).waypoint.pose.translation() - referencePosition).
norm();
797 return posDiff <= radius;
804 for (
int i =
static_cast<int>(idx) - 1; i >= 0; i--)
818 for (
int i = idx + 1; i < static_cast<int>(pts.size()); i++)
836 const std::vector<LocalTrajectoryPoint>&
842 std::vector<LocalTrajectoryPoint>&
851 const auto& finalTimestamp =
points().back().timestamp;
852 const auto timestamp =
859 const auto lower = std::lower_bound(pts.begin(), pts.end(), timestamp, cmp);
861 if (lower == pts.end() - 1)
867 const Duration d1 = timestamp - lower->timestamp;
868 const Duration dT = lower[1].timestamp - lower->timestamp;
871 const auto& global_T_wp_before = lower->pose;
874 const auto& global_T_wp_after = lower[1].pose;
877 const float t = d1 / dT;
878 math::LinearInterpolatedPose ip(
879 global_T_wp_before.matrix(), global_T_wp_after.matrix(), 0, 1,
true);
881 const core::Pose wp_before_T_wp_after = global_T_wp_before.inverse() * global_T_wp_after;
883 const Eigen::Matrix3f& global_R_wp_before = global_T_wp_before.linear();
886 const Eigen::Vector3f global_V_linear_movement_direction =
887 global_R_wp_before * wp_before_T_wp_after.translation().normalized();
888 const Eigen::Vector3f
distance = lower[1].pose.translation() - lower->pose.translation();
894 Eigen::AngleAxisf angleAx(wp_before_T_wp_after.linear());
897 .
linear = linearVelocity * global_V_linear_movement_direction,
900 return {
static_cast<core::Pose>(ip.Get(t)), feedforwardTwist};