SPFASmoothing.cpp
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#include "SPFASmoothing.h"
18
19#include <array>
20#include <cmath>
21#include <iomanip>
22#include <string>
23#include <vector>
24
25#include <Eigen/Geometry>
26
29
37
39{
40 namespace
41 {
43
44 core::GlobalTrajectory toGlobalTrajectory(const std::vector<CenterPoint>& traj)
45 {
46 core::GlobalTrajectory gtraj;
47 for (const auto& p : traj)
48 {
49 core::GlobalTrajectoryPoint gp;
50 gp.waypoint.pose =
51 Eigen::Translation3f{Eigen::Vector3f(static_cast<float>(p.x),
52 static_cast<float>(p.y),
53 0.0f)} *
54 Eigen::AngleAxisf{static_cast<float>(p.theta), Eigen::Vector3f::UnitZ()};
55 gp.velocity = static_cast<float>(p.v);
56 gtraj.mutablePoints().push_back(gp);
57 }
58 return gtraj;
59 }
60
61 std::vector<CenterPoint> toCenterTrajectory(const core::GlobalTrajectory& gtraj)
62 {
63 std::vector<CenterPoint> traj;
64 for (const auto& gp : gtraj.points())
65 {
67 p.x = gp.waypoint.pose.translation().x();
68 p.y = gp.waypoint.pose.translation().y();
69 const auto& R = gp.waypoint.pose.rotation();
70 p.theta = std::atan2(R(1, 0), R(0, 0));
71 p.v = gp.velocity;
72 traj.push_back(p);
73 }
74 return traj;
75 }
76
77 double queryDistance(const Costmap2DWrapper& wrapper, double x, double y)
78 {
79 double out;
80 wrapper(&x, &y, &out);
81 return out;
82 }
83
84 bool isInsideBounds(double x, double y, const algorithms::Costmap& costmap)
85 {
86 const auto local = costmap.origin().inverse() * Eigen::Vector2f{static_cast<float>(x),
87 static_cast<float>(y)};
88 const auto& bounds = costmap.getLocalSceneBounds();
89 return local.x() >= bounds.min.x() && local.x() <= bounds.max.x() &&
90 local.y() >= bounds.min.y() && local.y() <= bounds.max.y();
91 }
92
93 void pushWaypointsToSafeZone(std::vector<CenterPoint>& traj,
94 const Costmap2DWrapper& wrapper,
95 const algorithms::Costmap& costmap,
96 const std::vector<CenterPoint>& originalTargets,
97 double clearance,
98 double stepSize,
99 int maxIterations,
100 double maxDeviation)
101 {
102 const std::vector<std::pair<double, double>> neighbours = {
103 {0.0, 0.0},
104 {stepSize, 0.0},
105 {-stepSize, 0.0},
106 {0.0, stepSize},
107 {0.0, -stepSize},
108 {stepSize, stepSize},
109 {stepSize, -stepSize},
110 {-stepSize, stepSize},
111 {-stepSize, -stepSize},
112 };
113
114 for (int idx = 1; idx + 1 < static_cast<int>(traj.size()); ++idx)
115 {
116 CenterPoint& p = traj[idx];
117 const double origX = originalTargets[idx].x;
118 const double origY = originalTargets[idx].y;
119
120 auto withinDeviation = [&](double x, double y)
121 {
122 return std::hypot(x - origX, y - origY) <= maxDeviation + 1e-6;
123 };
124
125 double bestDist = queryDistance(wrapper, p.x, p.y);
126
127 if (bestDist >= clearance)
128 continue;
129
130 for (int iter = 0; iter < maxIterations; ++iter)
131 {
132 double bestX = p.x;
133 double bestY = p.y;
134 bool improved = false;
135
136 for (const auto& [dx, dy] : neighbours)
137 {
138 double candX = p.x + dx;
139 double candY = p.y + dy;
140 if (!isInsideBounds(candX, candY, costmap))
141 continue;
142 if (!withinDeviation(candX, candY))
143 continue;
144 double candDist = queryDistance(wrapper, candX, candY);
145 if (candDist > bestDist)
146 {
147 bestDist = candDist;
148 bestX = candX;
149 bestY = candY;
150 improved = true;
151 }
152 }
153
154 if (!improved)
155 break;
156
157 p.x = bestX;
158 p.y = bestY;
159
160 if (bestDist >= clearance)
161 break;
162 }
163
164 // Final safety projection: if still in collision, snap to the closest
165 // collision-free cell within the allowed deviation.
166 if (queryDistance(wrapper, p.x, p.y) <= 0.0)
167 {
168 const auto vertex = costmap.findClosestCollisionFreeVertex(
169 Eigen::Vector2f{static_cast<float>(origX), static_cast<float>(origY)},
170 static_cast<float>(maxDeviation));
171
172 if (vertex && withinDeviation(vertex->position.x(), vertex->position.y()))
173 {
174 p.x = vertex->position.x();
175 p.y = vertex->position.y();
176 }
177 }
178 }
179 }
180
181 bool validateTrajectory(const std::vector<CenterPoint>& traj, const std::string& label)
182 {
183 bool valid = true;
184 for (int i = 0; i < static_cast<int>(traj.size()); ++i)
185 {
186 if (!std::isfinite(traj[i].x) || !std::isfinite(traj[i].y) ||
187 !std::isfinite(traj[i].theta) || !std::isfinite(traj[i].v))
188 {
189 ARMARX_WARNING << "[" << label << "] NaN/Inf in traj[" << i
190 << "] : x=" << traj[i].x << " y=" << traj[i].y
191 << " theta=" << traj[i].theta << " v=" << traj[i].v;
192 valid = false;
193 }
194 }
195 return valid;
196 }
197
198 ceres::Solver::Options makeSolverOptions(const Params& params, int maxIterations)
199 {
200 ceres::Solver::Options options;
201 options.max_num_iterations = maxIterations;
202 options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
203 options.minimizer_progress_to_stdout = false;
204 options.num_threads = params.num_threads;
205 options.function_tolerance = 1e-6;
206 options.parameter_tolerance = 1e-8;
207 options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
208 options.initial_trust_region_radius = params.initial_trust_region_radius;
209 options.max_trust_region_radius = params.max_trust_region_radius;
210 options.min_trust_region_radius = params.min_trust_region_radius;
211 options.min_relative_decrease = 1e-4;
212 options.use_nonmonotonic_steps = true;
213 return options;
214 }
215
216 struct PassWeights
217 {
218 double w_obs;
219 double w_pose_smooth;
220 double w_spacing;
221 double w_tracking;
222 double w_safe_tracking;
223 };
224
225 double evalObstacleCost(const Costmap2DWrapper& wrapper,
226 double x,
227 double y,
228 double max_dist,
229 double clearance)
230 {
231 double d_raw;
232 wrapper(&x, &y, &d_raw);
233 if (!std::isfinite(d_raw))
234 return 100.0;
235
236 double obs_dist = d_raw - clearance;
237 if (obs_dist > max_dist)
238 return 0.0;
239 if (obs_dist < 0.0)
240 {
241 double penetration = -obs_dist;
242 double max_pen = 3.0 * max_dist;
243 if (penetration > max_pen)
244 penetration = max_pen;
245 double ratio = penetration / max_dist;
246 return std::exp(2.0 * ratio) - 1.0 + 0.1 * ratio;
247 }
248 return (max_dist - obs_dist) / max_dist;
249 }
250
251 void logResidualBreakdown(const std::vector<CenterPoint>& traj,
252 const Costmap2DWrapper& wrapper,
253 const std::vector<CenterPoint>& originalTargets,
254 const std::vector<CenterPoint>& safeTargets,
255 const Params& params,
256 const std::string& label)
257 {
258 const int N = static_cast<int>(traj.size());
259 if (N < 4)
260 return;
261
262 double c_obs_wp = 0.0;
263 double c_obs_seg = 0.0;
264 double c_smooth = 0.0;
265 double c_tracking = 0.0;
266 double c_safe_tracking = 0.0;
267 double c_spacing = 0.0;
268
269 // Obstacle (waypoints)
270 for (int i = 0; i < N; ++i)
271 {
272 double r = evalObstacleCost(wrapper, traj[i].x, traj[i].y, params.obs_max_distance, params.clearance);
273 c_obs_wp += r * r;
274 }
275
276 // Obstacle (segment samples)
277 for (int i = 0; i < N - 1; ++i)
278 {
279 for (int s = 1; s <= params.segment_obstacle_samples; ++s)
280 {
281 double t = static_cast<double>(s) / (params.segment_obstacle_samples + 1);
282 double mx = (1.0 - t) * traj[i].x + t * traj[i + 1].x;
283 double my = (1.0 - t) * traj[i].y + t * traj[i + 1].y;
284 double r = evalObstacleCost(wrapper, mx, my, params.obs_max_distance, params.clearance);
285 c_obs_seg += r * r;
286 }
287 }
288
289 // Position smoothness
290 for (int i = 1; i <= N - 2; ++i)
291 {
292 double rx = traj[i - 1].x - 2.0 * traj[i].x + traj[i + 1].x;
293 double ry = traj[i - 1].y - 2.0 * traj[i].y + traj[i + 1].y;
294 c_smooth += rx * rx + ry * ry;
295 }
296
297 // Bounded tracking to safe path
298 for (int i = 1; i <= N - 2; ++i)
299 {
300 double dx = traj[i].x - safeTargets[i].x;
301 double dy = traj[i].y - safeTargets[i].y;
302 double d = std::hypot(dx, dy);
303 double excess = d - params.tracking_deadzone;
304 if (excess > 0)
305 {
306 if (excess <= params.tracking_max_deviation - params.tracking_deadzone)
307 {
308 double r = params.w_tracking_in_bounds * excess;
309 c_tracking += r * r;
310 }
311 else
312 {
313 double over = excess - (params.tracking_max_deviation - params.tracking_deadzone);
314 double r = params.w_tracking_in_bounds * (params.tracking_max_deviation - params.tracking_deadzone)
315 + params.w_tracking_hard * over;
316 c_tracking += r * r;
317 }
318 }
319 }
320
321 // Soft tracking to original path
322 for (int i = 1; i <= N - 2; ++i)
323 {
324 double rx = traj[i].x - originalTargets[i].x;
325 double ry = traj[i].y - originalTargets[i].y;
326 // Use pass3 weight for breakdown (representative)
327 double w = params.pass3_w_tracking;
328 c_safe_tracking += (w * rx) * (w * rx) + (w * ry) * (w * ry);
329 }
330
331 // Spacing
332 double d_avg = computeAverageSpacing(traj);
333 if (d_avg <= 1e-9)
334 d_avg = 0.1;
335 for (int i = 0; i < N - 1; ++i)
336 {
337 double dx = traj[i + 1].x - traj[i].x;
338 double dy = traj[i + 1].y - traj[i].y;
339 double dist_sq = dx * dx + dy * dy;
340 double r = params.pass3_w_spacing * (dist_sq - d_avg * d_avg);
341 c_spacing += r * r;
342 }
343
344 double total = c_obs_wp + c_obs_seg + c_smooth + c_tracking + c_safe_tracking + c_spacing;
345
346 ARMARX_INFO << "=== Residual breakdown [" << label << "] ===";
347 ARMARX_INFO << "Obstacle (waypoints): " << std::scientific << std::setprecision(3) << c_obs_wp;
348 ARMARX_INFO << "Obstacle (segments): " << std::scientific << std::setprecision(3) << c_obs_seg;
349 ARMARX_INFO << "Position smoothness: " << std::scientific << std::setprecision(3) << c_smooth;
350 ARMARX_INFO << "Bounded tracking: " << std::scientific << std::setprecision(3) << c_tracking;
351 ARMARX_INFO << "Soft tracking: " << std::scientific << std::setprecision(3) << c_safe_tracking;
352 ARMARX_INFO << "Spacing: " << std::scientific << std::setprecision(3) << c_spacing;
353 ARMARX_INFO << "TOTAL: " << std::scientific << std::setprecision(3) << total;
354 }
355
356 void runPositionPass(std::vector<CenterPoint>& traj,
357 const Costmap2DWrapper& wrapper,
358 const std::vector<CenterPoint>& originalTargets,
359 const std::vector<CenterPoint>& safeTargets,
360 const PassWeights& w,
361 const Params& params,
362 int maxIterations)
363 {
364 const int N = static_cast<int>(traj.size());
365 if (N < 4)
366 {
367 ARMARX_INFO << "[SPFA smoothing] need at least 4 points for position pass";
368 return;
369 }
370
371 normalizeTrajectoryAngles(traj);
372
373 // Avoid zero-length segments.
374 for (int i = 1; i < N - 1; ++i)
375 {
376 double dx = traj[i].x - traj[i - 1].x;
377 double dy = traj[i].y - traj[i - 1].y;
378 if (std::hypot(dx, dy) < 1.0)
379 {
380 double ndx = (i + 1 < N) ? (traj[i + 1].x - traj[i].x) : 1.0;
381 double ndy = (i + 1 < N) ? (traj[i + 1].y - traj[i].y) : 0.0;
382 double nlen = std::hypot(ndx, ndy);
383 if (nlen < 1e-6)
384 {
385 ndx = 1.0;
386 ndy = 0.0;
387 nlen = 1.0;
388 }
389 traj[i].x += 1.0 * ndx / nlen;
390 traj[i].y += 1.0 * ndy / nlen;
391 }
392 }
393
394 ceres::Problem problem;
395 for (int i = 0; i < N; ++i)
396 problem.AddParameterBlock(&traj[i].x, 4);
397
398 problem.SetParameterBlockConstant(&traj.front().x);
399 problem.SetParameterBlockConstant(&traj.back().x);
400
401 // Position pass: only x, y are free.
402 for (int i = 1; i < N - 1; ++i)
403 {
404 std::vector<int> constant_indices = {2, 3}; // theta, v
405 SET_CONSTRAINT(problem, &traj[i].x, new SubsetConstraint(4, constant_indices));
406 }
407
408 // 1) Position smoothness
409 for (int i = 1; i <= N - 2; ++i)
410 {
411 problem.AddResidualBlock(
412 new ceres::AutoDiffCostFunction<PositionSmoothResidual, 2, 4, 4, 4>(
413 new PositionSmoothResidual(w.w_pose_smooth)),
414 nullptr,
415 &traj[i - 1].x,
416 &traj[i].x,
417 &traj[i + 1].x);
418 }
419
420 // 2) Spacing
421 double d_avg = computeAverageSpacing(traj);
422 if (d_avg <= 1e-9)
423 d_avg = 0.1;
424 for (int i = 0; i < N - 1; ++i)
425 {
426 problem.AddResidualBlock(
427 new ceres::AutoDiffCostFunction<SpacingResidual, 1, 4, 4>(
428 new SpacingResidual(d_avg, w.w_spacing)),
429 nullptr,
430 &traj[i].x,
431 &traj[i + 1].x);
432 }
433
434 // 3) Obstacle residuals (waypoints)
435 for (int i = 0; i < N; ++i)
436 {
437 problem.AddResidualBlock(
438 new ceres::AutoDiffCostFunction<ObstacleResidual2D, 1, 4>(
439 new ObstacleResidual2D(wrapper, w.w_obs, params.obs_max_distance, params.clearance)),
440 nullptr,
441 &traj[i].x);
442 }
443
444 // 4) Obstacle residuals along segments (interior samples)
445 for (int i = 0; i < N - 1; ++i)
446 {
447 for (int s = 1; s <= params.segment_obstacle_samples; ++s)
448 {
449 double t = static_cast<double>(s) / (params.segment_obstacle_samples + 1);
450 problem.AddResidualBlock(
451 new ceres::AutoDiffCostFunction<SegmentObstacleResidual2D, 1, 4, 4>(
452 new SegmentObstacleResidual2D(wrapper, w.w_obs, params.obs_max_distance, params.clearance, t)),
453 nullptr,
454 &traj[i].x,
455 &traj[i + 1].x);
456 }
457 }
458
459 // 5) Bounded tracking to the safe (hill-climbed) path
460 for (int i = 1; i <= N - 2; ++i)
461 {
462 problem.AddResidualBlock(
463 new ceres::AutoDiffCostFunction<BoundedTrackingResidual, 1, 4>(
464 new BoundedTrackingResidual(safeTargets[i].x,
465 safeTargets[i].y,
466 params.tracking_deadzone,
467 params.tracking_max_deviation,
468 params.w_tracking_in_bounds,
469 params.w_tracking_hard)),
470 nullptr,
471 &traj[i].x);
472 }
473
474 // 6) Soft tracking to the original SPFA path (weak, keeps deviation small)
475 if (w.w_tracking > 0.0)
476 {
477 for (int i = 1; i <= N - 2; ++i)
478 {
479 problem.AddResidualBlock(
480 new ceres::AutoDiffCostFunction<SoftTrackingResidual, 2, 4>(
481 new SoftTrackingResidual(originalTargets[i].x, originalTargets[i].y, w.w_tracking)),
482 nullptr,
483 &traj[i].x);
484 }
485 }
486
487 ceres::Solver::Options options = makeSolverOptions(params, maxIterations);
488 ceres::Solver::Summary summary;
489 ceres::Solve(options, &problem, &summary);
490
491 normalizeTrajectoryAngles(traj);
492
493 ARMARX_INFO << summary.FullReport();
494 ARMARX_INFO << "[Position pass] Final cost: " << summary.final_cost
495 << " iterations: " << summary.num_successful_steps
496 << " termination: " << summary.termination_type;
497 }
498
499 bool repairWaypoints(std::vector<CenterPoint>& traj,
500 const algorithms::Costmap& costmap,
501 const Costmap2DWrapper& wrapper,
502 const std::vector<CenterPoint>& originalTargets,
503 const Params& params)
504 {
505 const int N = static_cast<int>(traj.size());
506
507 for (int i = 1; i < N - 1; ++i)
508 {
509 double d = queryDistance(wrapper, traj[i].x, traj[i].y);
510 if (d > params.clearance)
511 continue;
512
513 const auto vertex = costmap.findClosestCollisionFreeVertex(
514 Eigen::Vector2f{static_cast<float>(originalTargets[i].x),
515 static_cast<float>(originalTargets[i].y)},
516 static_cast<float>(params.tracking_max_deviation));
517
518 if (!vertex)
519 return false;
520
521 const double dx = vertex->position.x() - originalTargets[i].x;
522 const double dy = vertex->position.y() - originalTargets[i].y;
523 if (std::hypot(dx, dy) > params.tracking_max_deviation + 1e-3)
524 return false;
525
526 traj[i].x = vertex->position.x();
527 traj[i].y = vertex->position.y();
528 }
529
530 return true;
531 }
532
533 double computeMaxDeviation(const std::vector<CenterPoint>& traj,
534 const std::vector<CenterPoint>& originalTargets)
535 {
536 double maxDev = 0.0;
537 for (std::size_t i = 0; i < traj.size(); ++i)
538 {
539 double dx = traj[i].x - originalTargets[i].x;
540 double dy = traj[i].y - originalTargets[i].y;
541 maxDev = std::max(maxDev, std::hypot(dx, dy));
542 }
543 return maxDev;
544 }
545 } // namespace
546
548 const algorithms::Costmap& costmap,
549 const Params& params) :
550 trajectory(trajectory),
551 costmap(costmap),
552 params(params)
553 {
554 }
555
557 {
558 Costmap2DWrapper wrapper{costmap};
559
560 std::vector<CenterPoint> traj = toCenterTrajectory(trajectory);
561 const std::vector<CenterPoint> originalTargets = traj;
562
563 if (!validateTrajectory(traj, "pre-hill-climb"))
564 {
565 ARMARX_WARNING << "[SPFA smoothing] Invalid trajectory before pre-processing. Aborting.";
566 return {std::nullopt, std::nullopt, false};
567 }
568
569 pushWaypointsToSafeZone(traj,
570 wrapper,
571 costmap,
572 originalTargets,
573 params.clearance,
574 params.hill_climb_step_size,
575 params.hill_climb_max_iterations,
576 params.tracking_max_deviation);
577
578 const std::vector<CenterPoint> safeTargets = traj;
579
580 if (!validateTrajectory(traj, "post-hill-climb"))
581 {
582 ARMARX_WARNING << "[SPFA smoothing] Invalid trajectory after pre-processing. Aborting.";
583 return {std::nullopt, std::nullopt, false};
584 }
585
586 logResidualBreakdown(traj, wrapper, originalTargets, safeTargets, params, "after pre-processing");
587
588 // Multi-pass position optimization.
589 const std::array<PassWeights, 3> passes = {
590 PassWeights{params.pass1_w_obs,
591 params.pass1_w_pose_smooth,
592 params.pass1_w_spacing,
593 params.pass1_w_tracking,
594 params.pass1_w_safe_tracking},
595 PassWeights{params.pass2_w_obs,
596 params.pass2_w_pose_smooth,
597 params.pass2_w_spacing,
598 params.pass2_w_tracking,
599 params.pass2_w_safe_tracking},
600 PassWeights{params.pass3_w_obs,
601 params.pass3_w_pose_smooth,
602 params.pass3_w_spacing,
603 params.pass3_w_tracking,
604 params.pass3_w_safe_tracking}};
605
606 for (size_t pass = 0; pass < passes.size(); ++pass)
607 {
608 ARMARX_INFO << "[SPFA smoothing] Starting position pass " << (pass + 1);
609 runPositionPass(traj, wrapper, originalTargets, safeTargets, passes[pass], params, params.max_iterations);
610 logResidualBreakdown(traj, wrapper, originalTargets, safeTargets, params,
611 "after position pass " + std::to_string(pass + 1));
612
613 if (!validateTrajectory(traj, "post-position-pass-" + std::to_string(pass + 1)))
614 {
615 ARMARX_WARNING << "[SPFA smoothing] NaN/Inf after position pass " << (pass + 1)
616 << ". Reverting to pre-processed safe path.";
617 traj = safeTargets;
618 break;
619 }
620 }
621
622 normalizeTrajectoryAngles(traj);
623
624 // Collision repair if needed.
625 TrajectoryChecker2D checker(costmap, params.clearance);
626 core::GlobalTrajectory smoothedTrajectory = toGlobalTrajectory(traj);
627 bool collisionFree = checker.check(smoothedTrajectory);
628
629 if (!collisionFree)
630 {
631 ARMARX_WARNING << "[SPFA smoothing] Initial smoothing has collisions. Running repair pass.";
632
633 if (!repairWaypoints(traj, costmap, wrapper, originalTargets, params))
634 {
635 ARMARX_ERROR << "[SPFA smoothing] Repair failed: could not project colliding waypoints "
636 "to collision-free positions within max deviation.";
637 }
638 else
639 {
640 PassWeights repairWeights{params.repair_w_obs,
641 params.repair_w_pose_smooth,
642 params.repair_w_spacing,
643 params.repair_w_tracking,
644 params.repair_w_safe_tracking};
645 runPositionPass(traj, wrapper, originalTargets, safeTargets, repairWeights, params, params.repair_max_iterations);
646 logResidualBreakdown(traj, wrapper, originalTargets, safeTargets, params, "after repair pass");
647
648 smoothedTrajectory = toGlobalTrajectory(traj);
649 collisionFree = checker.check(smoothedTrajectory);
650 }
651 }
652
653 const double maxDeviation = computeMaxDeviation(traj, originalTargets);
654 const bool deviationOk = maxDeviation <= params.tracking_max_deviation + 1e-3;
655
656 if (collisionFree && deviationOk)
657 {
658 ARMARX_INFO << "[SPFA smoothing] Smoothed trajectory is collision-free. Max deviation: "
659 << maxDeviation << " mm";
660 }
661 else
662 {
663 if (!collisionFree)
664 ARMARX_WARNING << "[SPFA smoothing] Smoothed trajectory still has collisions after repair.";
665 if (!deviationOk)
666 ARMARX_WARNING << "[SPFA smoothing] Max deviation too large: " << maxDeviation
667 << " mm (limit: " << params.tracking_max_deviation << " mm).";
668 }
669
670 for (int i = 0; i < static_cast<int>(traj.size()); ++i)
671 {
672 ARMARX_DEBUG << std::fixed << std::setprecision(3) << "i=" << i << " : x=" << traj[i].x
673 << " y=" << traj[i].y << " theta=" << traj[i].theta << " v=" << traj[i].v;
674 }
675
676 const core::GlobalTrajectory preprocessedTrajectory = toGlobalTrajectory(safeTargets);
677 const bool success = collisionFree && deviationOk;
678 return {smoothedTrajectory, preprocessedTrajectory, success};
679 }
680
681} // namespace armarx::navigation::algorithms::spfa::smoothing
Differentiable wrapper around the standard 2-D distance-to-obstacle costmap.
SPFASmoothing(const core::GlobalTrajectory &trajectory, const algorithms::Costmap &costmap, const Params &params)
bool check(const core::GlobalTrajectory &trajectory, bool logDetails=false) const
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#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
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
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
std::multimap< std::string, std::string > Params
Definition httplib.h:510
bool isfinite(const std::vector< T, Ts... > &v)
Definition algorithm.h:366
ceres::SubsetParameterization SubsetConstraint
This file is part of ArmarX.
Definition residuals.h:22
#define SET_CONSTRAINT(problem, param, constraint)
Definition residuals.h:23