PathGeometry.h
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <cstddef>
20#include <vector>
21
23
25{
26 /**
27 * @brief Thresholds for what counts as a geometrically usable path.
28 *
29 * Separate from the smoothing weights: these describe the *result* the optimizer has to
30 * produce, not how it gets there.
31 */
33 {
34 /// Consecutive travel directions whose dot product is below this have reversed. Slightly
35 /// above zero so a numerically flat vertex is not reported as a fold.
36 double minDirectionDot = 0.0;
37
38 /// Segments shorter than this [mm] carry no reliable direction, and the heading a
39 /// downstream spline reads off them is numerical noise.
40 double minSegmentLength = 1.0;
41
42 /**
43 * @brief Most the commanded heading may turn per millimetre travelled [rad/mm].
44 *
45 * A path-length bound, not a rate: `yaw'(s) * v` is the yaw rate the base is asked for,
46 * so a profile that turns faster than this per millimetre can only be executed by
47 * slowing down, and past some point by not moving at all.
48 *
49 * The default is what a base holding `limits.angular` (0.8 rad/s on ARMAR-7) can turn
50 * while still making the `boundaryVelocity` the profile is floored at (150 mm/s):
51 * 0.8 / 150 = 0.00533 rad/mm. Healthy ARMAR-7 runs measure 0.0016 rad/mm at their worst;
52 * the run this bound was derived from reached 0.0259.
53 */
54 double maxTurnRate = 0.8 / 150.0; // [rad/mm]
55 };
56
57 /**
58 * @brief Indices of waypoints that make the path double back on itself.
59 *
60 * Nothing in the smoother's cost function can see a fold: `SpacingResidual` compares *squared*
61 * distances and so is blind to direction, and `PositionSmoothResidual` -- the discrete second
62 * difference -- is zero for any point on the line through its neighbours, including one placed
63 * behind its predecessor. The only acceptance gate the caller had was a collision check, which
64 * a fold passes happily.
65 *
66 * A fold matters downstream because the reparametrization fits a spline through the path with
67 * the *polyline* arc length as its parameter. That parameter keeps increasing through a
68 * reversal, so nothing rejects it, but the spline tangent collapses at the cusp -- measured at
69 * ~1/60 of its nominal unit norm for a single waypoint displaced 30 mm backwards. The velocity
70 * bound is `v(s) * |p'(s)|` and is only equivalent to a speed limit while `|p'| == 1`, so the
71 * solver is driven to a near-zero path speed exactly there: the robot stops mid-path.
72 *
73 * Start and goal are never reported -- they are commanded, not optimized.
74 */
75 std::vector<std::size_t> findGeometryViolations(const core::GlobalTrajectory& trajectory,
76 const GeometryLimits& limits = {});
77
78 /**
79 * @brief Drop the offending waypoints, repeating until the path is monotone.
80 *
81 * Removing a waypoint is the right repair rather than rejecting the whole result: a fold is
82 * normally one point that overshot, and `BoundedTrackingResidual` keeps its neighbours near
83 * the reference path, so the remainder is still the path the optimizer intended. Removing one
84 * point does create a new segment between its neighbours, which can cut a corner -- the caller
85 * must re-run the collision check on the result.
86 *
87 * @param removed Receives the indices removed, in terms of the *original* trajectory.
88 * @return The repaired trajectory. Unchanged if there was nothing to repair.
89 */
91 std::vector<std::size_t>& removed,
92 const GeometryLimits& limits = {});
93
94 /**
95 * @brief Segments whose commanded heading turns faster than the base could follow.
96 *
97 * A separate failure from a fold, and one the fold check cannot see: the *position* path can
98 * be perfectly smooth -- on the run this was derived from its tangent held to within 0.08 deg
99 * per segment -- while the orientation assigned to it sweeps 116 deg over 300 mm. Both
100 * checks pass such a path today, and the reparametrization then has to choose between
101 * violating the angular limit and stopping.
102 *
103 * Reported per segment, as the index of the waypoint the segment starts at.
104 *
105 * Unlike a fold this is not repairable by dropping waypoints: the rotation is spread over
106 * many of them and removing any subset only makes the remaining ones turn faster. The caller
107 * has to discard the profile and fall back to one it can execute.
108 */
109 std::vector<std::size_t> findTurnRateViolations(const core::GlobalTrajectory& trajectory,
110 const GeometryLimits& limits = {});
111
112 /// The largest `|dyaw| / segment length` in the trajectory [rad/mm]. Zero for fewer than two
113 /// points. Reported so a caller can log how far out a rejected profile was.
114 double maxTurnRate(const core::GlobalTrajectory& trajectory, const GeometryLimits& limits = {});
115
116} // namespace armarx::navigation::algorithms::spfa::smoothing
std::vector< std::size_t > findTurnRateViolations(const core::GlobalTrajectory &trajectory, const GeometryLimits &limits)
Segments whose commanded heading turns faster than the base could follow.
double maxTurnRate(const core::GlobalTrajectory &trajectory, const GeometryLimits &limits)
The largest |dyaw| / segment length in the trajectory [rad/mm].
std::vector< std::size_t > findGeometryViolations(const core::GlobalTrajectory &trajectory, const GeometryLimits &limits)
Indices of waypoints that make the path double back on itself.
core::GlobalTrajectory repairGeometry(const core::GlobalTrajectory &trajectory, std::vector< std::size_t > &removed, const GeometryLimits &limits)
Drop the offending waypoints, repeating until the path is monotone.
Thresholds for what counts as a geometrically usable path.
double minSegmentLength
Segments shorter than this [mm] carry no reliable direction, and the heading a downstream spline read...
double minDirectionDot
Consecutive travel directions whose dot product is below this have reversed.
double maxTurnRate
Most the commanded heading may turn per millimetre travelled [rad/mm].