Smoothing.cpp
Go to the documentation of this file.
1#include "Smoothing.h"
2
3#include <cmath>
4#include <iomanip>
5//#include <ios>
6#include <vector>
7
8#include <Eigen/Geometry>
9
12
20
22{
24 const Costmap3D& costmap3d,
25 const Params& params) :
26 trajectory(trajectory), costmap3d(costmap3d), params(params)
27 {
28 }
29
30 // convert back to global trajectory
32 toGlobalTrajectory(const std::vector<CenterPoint>& traj)
33 {
35 for (const auto& p : traj)
36 {
38 gp.waypoint.pose =
39 Eigen::Translation3f{
40 Eigen::Vector3f(static_cast<float>(p.x), static_cast<float>(p.y), 0.0f)} *
41 Eigen::AngleAxisf{static_cast<float>(p.theta), Eigen::Vector3f::UnitZ()};
42 gp.velocity = static_cast<float>(p.v);
43 gtraj.mutablePoints().push_back(gp);
44 }
45 return gtraj;
46 }
47
48 // convert global trajectory to trajectory for smoothing
49 std::vector<CenterPoint>
51 {
52 std::vector<CenterPoint> traj;
53 for (const auto& gp : gtraj.points())
54 {
56 p.x = gp.waypoint.pose.translation().x();
57 p.y = gp.waypoint.pose.translation().y();
58 const auto& R = gp.waypoint.pose.rotation();
59 p.theta = std::atan2(R(1, 0), R(0, 0));
60 p.v = gp.velocity;
61 traj.push_back(p);
62 }
63 return traj;
64 }
65
66 static double
67 queryDistance(const Costmap3DWrapper& wrapper, double x, double y, double theta)
68 {
69 double out;
70 wrapper(&x, &y, &theta, &out);
71 return out;
72 }
73
74 // Pre-process: push interior waypoints into the safe zone by hill-climbing
75 // on the signed-distance field. The SDF's local maxima are at corridor
76 // centres, so this naturally places waypoints in the middle of free space.
77 static void
78 pushWaypointsToSafeZone(std::vector<CenterPoint>& traj,
79 const Costmap3DWrapper& wrapper,
80 const Costmap3D& costmap,
81 double clearance,
82 double stepSize,
83 int maxIterations)
84 {
85 // 8-neighbour offsets plus zero (stay in place)
86 const std::vector<std::pair<double, double>> neighbours = {
87 {0.0, 0.0},
88 {stepSize, 0.0},
89 {-stepSize, 0.0},
90 {0.0, stepSize},
91 {0.0, -stepSize},
92 {stepSize, stepSize},
93 {stepSize, -stepSize},
94 {-stepSize, stepSize},
95 {-stepSize, -stepSize},
96 };
97
98 auto isInsideBounds = [&costmap](double x, double y) -> bool
99 {
100 const auto local = costmap.origin().inverse() *
101 Eigen::Vector2f{static_cast<float>(x), static_cast<float>(y)};
102 const auto& bounds = costmap.getLocalSceneBounds();
103 return local.x() >= bounds.min.x() && local.x() <= bounds.max.x() &&
104 local.y() >= bounds.min.y() && local.y() <= bounds.max.y();
105 };
106
107 for (int idx = 1; idx + 1 < static_cast<int>(traj.size()); ++idx)
108 {
109 CenterPoint& p = traj[idx];
110 double bestDist = queryDistance(wrapper, p.x, p.y, p.theta);
111
112 if (bestDist >= clearance)
113 continue; // already safe
114
115 for (int iter = 0; iter < maxIterations; ++iter)
116 {
117 double bestX = p.x;
118 double bestY = p.y;
119 bool improved = false;
120
121 for (const auto& [dx, dy] : neighbours)
122 {
123 double candX = p.x + dx;
124 double candY = p.y + dy;
125 if (!isInsideBounds(candX, candY))
126 continue; // reject out-of-bounds candidates
127 double candDist = queryDistance(wrapper, candX, candY, p.theta);
128 if (candDist > bestDist)
129 {
130 bestDist = candDist;
131 bestX = candX;
132 bestY = candY;
133 improved = true;
134 }
135 }
136
137 if (!improved)
138 {
139 // Local maximum (narrow corridor). Stay at best available.
140 break;
141 }
142
143 p.x = bestX;
144 p.y = bestY;
145
146 if (bestDist >= clearance)
147 break; // reached safe zone
148 }
149 }
150 }
151
154 {
155 Costmap3DWrapper costmapWrapper{costmap3d};
156
157 std::vector<CenterPoint> traj;
158 {
159 traj = toCenterTrajectory(trajectory);
160 }
161
162 // Stage 1: Pre-process waypoints into the safe zone.
163 // The SDF's local maxima are at corridor centres, so hill-climbing
164 // naturally places waypoints in the middle of free space.
165 pushWaypointsToSafeZone(traj,
166 costmapWrapper,
167 costmap3d,
168 params.clearance,
169 params.hill_climb_step_size,
170 params.hill_climb_max_iterations);
171
172 // Stage 2: Ceres smoothing with the safe positions as tracking targets.
173 // Tracking now cooperates with obstacle avoidance because it pulls
174 // toward an already-safe path.
175 std::vector<CenterPoint> traj_targets = traj;
176 optimizeTrajectoryCeres(traj, costmapWrapper, traj_targets, params);
177
178 TrajectoryChecker checker(costmap3d);
179 auto checkResult = checker.check(toGlobalTrajectory(traj));
180 bool collisionFree = checkResult.isCollisionFree();
181 if (collisionFree)
182 {
183 ARMARX_INFO << "Smoothed trajectory is collision-free.";
184 }
185 else
186 {
187 ARMARX_WARNING << "Smoothed trajectory still has collision after pre-processing.";
188 }
189
190 for (int i = 0; i < static_cast<int>(traj.size()); ++i)
191 {
192 ARMARX_DEBUG << std::fixed << std::setprecision(3) << "i=" << i << " : x=" << traj[i].x
193 << " y=" << traj[i].y << " theta=" << traj[i].theta << " v=" << traj[i].v;
194 }
195
196 return {toGlobalTrajectory(traj), toGlobalTrajectory(traj_targets), collisionFree};
197 }
198
199} // namespace armarx::navigation::algorithms::orientation_aware::smoothing
TrajectoryCollisionCheckResult check(const core::GlobalTrajectory &trajectory, bool logDetails=false) const
Smoothing(const core::GlobalTrajectory &trajectory, const Costmap3D &costmap3d, const Params &params)
Definition Smoothing.cpp:23
const std::vector< GlobalTrajectoryPoint > & points() const
std::vector< GlobalTrajectoryPoint > & mutablePoints()
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
void optimizeTrajectoryCeres(std::vector< CenterPoint > &traj, const Costmap3DWrapper &costmap_wrapper, const std::vector< CenterPoint > &traj_targets, const io::SmoothingParams &opts)
Definition residuals.h:1109
std::vector< CenterPoint > toCenterTrajectory(const armarx::navigation::core::GlobalTrajectory &gtraj)
Definition Smoothing.cpp:50
armarx::navigation::core::GlobalTrajectory toGlobalTrajectory(const std::vector< CenterPoint > &traj)
Definition Smoothing.cpp:32
This file offers overloads of toIce() and fromIce() functions for STL container types.