15#include <ceres/ceres.h>
17#if CERES_VERSION_MAJOR >= 2 && CERES_VERSION_MINOR >= 1
18# include <ceres/manifold.h>
20# define SET_CONSTRAINT(problem, param, constraint) \
21 (problem).SetManifold((param), (constraint))
23# include <ceres/local_parameterization.h>
25# define SET_CONSTRAINT(problem, param, constraint) \
26 (problem).SetParameterization((param), (constraint))
55 return ceres::atan2(ceres::sin(diff), ceres::cos(diff));
61 return std::atan2(std::sin(a), std::cos(a));
65 normalizeTrajectoryAngles(std::vector<CenterPoint>& traj)
78 double t = (
x - edge0) / (edge1 - edge0);
79 return t * t * (3.0 - 2.0 * t);
84 double fade_start_clearance,
85 double fade_end_clearance)
88 return 1.0 -
smoothstep(fade_start_clearance, fade_end_clearance, clearance);
97 if constexpr (std::is_arithmetic_v<T>)
100 return ceres::exp(
x);
103 template <
typename T>
107 if constexpr (std::is_arithmetic_v<T>)
110 return ceres::log(
x);
118 template <
typename T>
124 if (values.size() == 1)
127 T min_val = values[0];
128 for (
const auto& v : values)
133 for (
const auto& v : values)
135 T arg = -alpha * (v - min_val);
145 static std::pair<int, int>
146 getDiscreteOrientationBracket(
double theta_rad,
int num_orientations)
148 double deg = theta_rad * 180.0 /
M_PI;
155 double deg_per = 360.0 / num_orientations;
156 int lower =
static_cast<int>(std::floor(deg / deg_per));
157 int upper = lower + 1;
159 lower += num_orientations;
160 if (upper >= num_orientations)
161 upper -= num_orientations;
162 return {lower, upper};
177 template <
typename T>
181 const T*
const c_next,
184 residual[0] =
T(
pos_w) * (c_prev[0] -
T(2.0) * c_i[0] + c_next[0]);
185 residual[1] =
T(
pos_w) * (c_prev[1] -
T(2.0) * c_i[1] + c_next[1]);
189 residual[2] =
T(
ori_w) * (dprev - dnext);
204 template <
typename T>
206 operator()(
const T*
const theta0,
const T*
const theta1,
T* residuals)
const
210 residuals[0] =
T(
w_) * d;
225 template <
typename T>
245 template <
typename T>
249 T dv = c_ip1[3] - c_i[3];
255 residual[0] =
T(0.0);
272 template <
typename T>
294 template <
typename T>
299 if (v_above_min <
T(0))
301 residual[0] =
T(
w) * v_above_min *
T(
danger_);
317 template <
typename T>
325 residual[0] =
T(
w) * (c_m2[0] -
T(3.0) * c_m1[0] +
T(3.0) * c_i[0] - c_p1[0]);
326 residual[1] =
T(
w) * (c_m2[1] -
T(3.0) * c_m1[1] +
T(3.0) * c_i[1] - c_p1[1]);
328 T a_m2 = c_m2[2], a_m1 = c_m1[2], a_i = c_i[2], a_p1 = c_p1[2];
331 residual[2] =
T(
w) * r;
353 bool use_fuzzy_orientation =
true,
354 int num_orientations = 72,
355 int fuzzy_window_bins = 2,
356 double fuzzy_alpha = 5.0) :
369 template <
typename T>
376 T theta_query = node[2];
386 std::vector<T> samples;
390 T theta_sample = theta_query +
T(
static_cast<double>(k) * bin_size);
392 wrapper_(&node[0], &node[1], &theta_sample, &d_sample);
393 samples.push_back(d_sample);
399 wrapper_(&node[0], &node[1], &theta_query, &obs_dist_raw);
404 if (!ceres::isfinite(obs_dist_raw))
406 residual[0] =
T(
w_) *
T(100.0);
412 if (obs_dist_raw < min_allowed)
413 obs_dist_raw = min_allowed;
419 if (obs_dist >=
T(0.0))
422 residual[0] =
T(0.0);
429 T penetration = -obs_dist;
431 if (penetration > max_pen)
432 penetration = max_pen;
437 T r =
T(0.5) * (ceres::sqrt(penetration * penetration + eps * eps) + penetration)
439 residual[0] =
T(
w_) * r;
466 bool use_fuzzy_orientation =
true,
467 int num_orientations = 72,
468 int fuzzy_window_bins = 2,
469 double fuzzy_alpha = 5.0) :
482 template <
typename T>
486 T mx = (c_i[0] + c_ip1[0]) /
T(2.0);
487 T my = (c_i[1] + c_ip1[1]) /
T(2.0);
488 T mtheta = c_i[2] +
angleDiff(c_ip1[2], c_i[2]) /
T(2.0);
492 T theta_query = mtheta;
501 std::vector<T> samples;
505 T theta_sample = theta_query +
T(
static_cast<double>(k) * bin_size);
507 wrapper_(&mx, &my, &theta_sample, &d_sample);
508 samples.push_back(d_sample);
514 wrapper_(&mx, &my, &theta_query, &obs_dist_raw);
519 if (!ceres::isfinite(obs_dist_raw))
521 residual[0] =
T(
w_) *
T(100.0);
527 if (obs_dist_raw < min_allowed)
528 obs_dist_raw = min_allowed;
532 if (obs_dist >=
T(0.0))
535 residual[0] =
T(0.0);
540 T penetration = -obs_dist;
542 if (penetration > max_pen)
543 penetration = max_pen;
546 T r =
T(0.5) * (ceres::sqrt(penetration * penetration + eps * eps) + penetration)
548 residual[0] =
T(
w_) * r;
579 template <
typename T>
583 residual[0] =
T(
wx_) * (c_i[0] -
T(
xr_));
584 residual[1] =
T(
wy_) * (c_i[1] -
T(
yr_));
586 residual[3] =
T(
wv_) * (c_i[3] -
T(
vr_));
601 template <
typename T>
608 residual[0] =
T(
w) * diff;
610 residual[0] =
T(0.0);
627 template <
typename T>
631 T cx =
c[0], cy =
c[1], cth =
c[2];
632 T ccos = ceres::cos(cth), csin = ceres::sin(cth);
633 rx = cx + ccos *
T(
dx_) - csin *
T(
dy_);
634 ry = cy + csin *
T(
dx_) + ccos *
T(
dy_);
638 template <
typename T>
642 const T*
const c_next,
645 T rpx, rpy, rpth, rix, riy, rith, rnx, rny, rnth;
649 residual[0] =
T(
w) * (rpx -
T(2.0) * rix + rnx);
650 residual[1] =
T(
w) * (rpy -
T(2.0) * riy + rny);
675 template <
typename T>
679 T cx =
c[0], cy =
c[1], cth =
c[2];
680 T ccos = ceres::cos(cth), csin = ceres::sin(cth);
681 rx = cx + ccos *
T(-0.5) - csin *
T(0.0);
682 ry = cy + csin *
T(-0.5) + ccos *
T(0.0);
685 template <
typename T>
696 const T dist_eps =
T(1e-6);
697 T dist = ceres::sqrt(dx * dx + dy * dy + dist_eps * dist_eps);
700 residual[0] =
T(
w_) *
T(0.5)
701 * (ceres::sqrt(y * y +
T(
eps_ *
eps_)) + y);
718 template <
typename T>
722 T dx = c_ip1[0] - c_i[0];
723 T dy = c_ip1[1] - c_i[1];
724 T dist_sq = dx * dx + dy * dy;
726 residual[0] =
T(
w) * (dist_sq - target_sq);
741 double linear_weight,
742 double quadratic_weight,
743 double relative_deviation_threshold) :
751 template <
typename T>
755 T dx = c_ip1[0] - c_i[0];
756 T dy = c_ip1[1] - c_i[1];
757 T dist_sq = dx * dx + dy * dy;
759 T dist = ceres::sqrt(dist_sq +
T(1e-12));
760 T rel_dev = ceres::abs(dist /
T(
d_avg_) -
T(1.0));
784 return std::hypot(b.
x - a.x, b.
y - a.y);
788 computeAverageSpacing(
const std::vector<CenterPoint>& traj)
793 for (
size_t i = 0; i + 1 < traj.size(); ++i)
794 sum += segment_length(traj[i], traj[i + 1]);
795 return sum / double(traj.size() - 1);
802 logResidualBreakdown(
const std::vector<CenterPoint>& traj,
803 const Costmap3DWrapper& wrapper,
804 const std::vector<CenterPoint>&
targets,
805 const std::vector<double>& tracking_scales,
806 const io::SmoothingParams& opts)
808 const int N =
static_cast<int>(traj.size());
809 double c_obs = 0.0, c_mid_obs = 0.0, c_pose_smooth = 0.0, c_start_rot = 0.0,
810 c_vel_smooth = 0.0, c_jerk = 0.0, c_robot_smooth = 0.0, c_spacing = 0.0,
811 c_tracking = 0.0, c_robot_pose_proximity = 0.0;
813 auto evalObsAtTheta = [&](
double x,
double y,
double th) ->
double
816 wrapper(&
x, &y, &th, &d_raw);
817 double d = d_raw - opts.clearance;
821 double max_pen = 3.0 * opts.obs_max_distance;
824 const double eps = opts.obs_barrier_eps_mm;
826 const double r = 0.5 * (std::sqrt(pen * pen + eps * eps) + pen) - 0.5 * eps;
827 return opts.w_obs * r;
832 auto evalObsFuzzy = [&](
double x,
double y,
double theta_query) ->
double
834 if (!opts.use_fuzzy_orientation)
835 return evalObsAtTheta(
x, y, theta_query);
838 if (opts.fuzzy_orientation_window_bins > 0)
842 const double bin_size = 2.0 *
M_PI / 72.0;
843 std::vector<double> samples;
844 samples.reserve(2 * opts.fuzzy_orientation_window_bins + 1);
845 for (
int k = -opts.fuzzy_orientation_window_bins;
846 k <= opts.fuzzy_orientation_window_bins;
849 double theta_sample = theta_query +
static_cast<double>(k) * bin_size;
851 wrapper(&
x, &y, &theta_sample, &d_sample);
852 samples.push_back(d_sample);
854 d_raw =
smoothMin(samples, opts.fuzzy_orientation_alpha);
858 wrapper(&x, &y, &theta_query, &d_raw);
862 const double min_allowed = -3.0 * opts.obs_max_distance;
863 if (d_raw < min_allowed)
866 double d = d_raw - opts.clearance;
870 double max_pen = 3.0 * opts.obs_max_distance;
873 const double eps = opts.obs_barrier_eps_mm;
875 const double r = 0.5 * (std::sqrt(pen * pen + eps * eps) + pen) - 0.5 * eps;
876 return opts.w_obs * r;
884 for (
int i = 0; i < N; ++i)
886 double r = evalObsFuzzy(traj[i].x, traj[i].y, traj[i].theta);
889 for (
int i = 0; i < N - 1; ++i)
893 +
angleDiff(traj[i + 1].theta, traj[i].theta) / 2.0);
894 double mx = (traj[i].x + traj[i + 1].x) / 2.0;
895 double my = (traj[i].y + traj[i + 1].y) / 2.0;
896 double r = evalObsFuzzy(mx, my, midTheta);
902 for (
int i = 1; i <= N - 2; ++i)
904 double rx = traj[i - 1].x - 2.0 * traj[i].x + traj[i + 1].x;
905 double ry = traj[i - 1].y - 2.0 * traj[i].y + traj[i + 1].y;
908 double rth = dprev - dnext;
909 c_pose_smooth += (opts.w_pose_smooth * rx) * (opts.w_pose_smooth * rx)
910 + (opts.w_pose_smooth * ry) * (opts.w_pose_smooth * ry)
911 + (opts.w_orientation_smooth * rth) * (opts.w_orientation_smooth * rth);
918 c_start_rot += (opts.w_boundary * d) * (opts.w_boundary * d);
920 c_start_rot += (opts.w_boundary * d) * (opts.w_boundary * d);
924 for (
int i = 0; i < N - 1; ++i)
926 double dv = traj[i + 1].v - traj[i].v;
927 if (dv > opts.max_accel_per_segment)
928 c_vel_smooth += (opts.w_accel_decel_limit * (dv - opts.max_accel_per_segment))
929 * (opts.w_accel_decel_limit * (dv - opts.max_accel_per_segment));
930 else if (dv < -opts.max_decel_per_segment)
931 c_vel_smooth += (opts.w_accel_decel_limit * (-dv - opts.max_decel_per_segment))
932 * (opts.w_accel_decel_limit * (-dv - opts.max_decel_per_segment));
936 double v_nominal = (N >= 3) ? traj[1].v : traj.front().
v;
937 for (
int i = 1; i < N - 1; ++i)
939 double rv = traj[i].v - v_nominal;
940 c_vel_smooth += (opts.w_nominal_velocity * rv) * (opts.w_nominal_velocity * rv);
944 for (
int i = 1; i < N - 1; ++i)
947 wrapper(&traj[i].x, &traj[i].y, &traj[i].theta, &d);
948 double danger = std::clamp((opts.slow_down_distance - d) / opts.slow_down_distance,
951 double v_above_min = std::max(traj[i].v - opts.min_velocity_near_obstacle, 0.0);
953 (opts.w_velocity_proximity * v_above_min * danger)
954 * (opts.w_velocity_proximity * v_above_min * danger);
958 if (opts.use_jerk && N >= 4)
960 for (int i = 2; i <= N - 2; ++i)
962 double rx = traj[i - 2].x - 3.0 * traj[i - 1].x + 3.0 * traj[i].x - traj[i + 1].x;
963 double ry = traj[i - 2].y - 3.0 * traj[i - 1].y + 3.0 * traj[i].y - traj[i + 1].y;
964 double r = normalizeAngle(traj[i - 2].theta - traj[i].theta)
965 - 3.0 * normalizeAngle(traj[i - 1].theta - traj[i].theta)
966 + 3.0 * normalizeAngle(traj[i].theta - traj[i].theta)
967 - normalizeAngle(traj[i + 1].theta - traj[i].theta);
968 c_jerk += (opts.w_pose_jerk * rx) * (opts.w_pose_jerk * rx)
969 + (opts.w_pose_jerk * ry) * (opts.w_pose_jerk * ry)
970 + (opts.w_pose_jerk * r) * (opts.w_pose_jerk * r);
975 if (opts.use_robot_smooth)
977 for (int i = 1; i <= N - 2; ++i)
979 auto c2r = [](const CenterPoint& c, double& rx, double& ry, double& rth)
981 double ccos = std::cos(c.theta), csin = std::sin(c.theta);
982 rx = c.x + ccos * (-0.5) - csin * (0.0);
983 ry = c.y + csin * (-0.5) + ccos * (0.0);
986 double rpx, rpy, rpth, rix, riy, rith, rnx, rny, rnth;
987 c2r(traj[i - 1], rpx, rpy, rpth);
988 c2r(traj[i], rix, riy, rith);
989 c2r(traj[i + 1], rnx, rny, rnth);
990 double rx = opts.w_robot_smooth * (rpx - 2.0 * rix + rnx);
991 double ry = opts.w_robot_smooth * (rpy - 2.0 * riy + rny);
992 double rth = opts.w_robot_smooth
993 * (normalizeAngle(rpth - rith) - normalizeAngle(rnth - rith));
994 c_robot_smooth += rx * rx + ry * ry + rth * rth;
1000 for (
int i = 0; i + 1 < N; ++i)
1001 d_avg += std::hypot(traj[i + 1].
x - traj[i].
x, traj[i + 1].y - traj[i].y);
1006 for (
int i = 0; i + 1 < N; ++i)
1008 double dist = std::hypot(traj[i + 1].
x - traj[i].
x, traj[i + 1].y - traj[i].y);
1009 if (opts.use_soft_spacing)
1011 double rel_dev = std::abs(dist / d_avg - 1.0);
1012 double r = opts.w_spacing_linear * rel_dev;
1013 double excess = rel_dev - opts.spacing_relative_deviation_threshold;
1016 r += opts.w_spacing_quadratic * excess * excess;
1022 double r = opts.w_spacing * (dist * dist - d_avg * d_avg);
1028 if (opts.use_tracking &&
static_cast<int>(targets.size()) == N)
1030 for (
int i = 0; i < N; ++i)
1032 double s = tracking_scales[i];
1033 double wx = opts.w_track *
s, wy = opts.w_track *
s,
1034 wth = opts.w_track * 300.0 *
s, wv = opts.w_track * 0.2 *
s;
1035 double rx = wx * (traj[i].x - targets[i].x);
1036 double ry = wy * (traj[i].y - targets[i].y);
1037 double rth = wth *
normalizeAngle(traj[i].theta - targets[i].theta);
1038 double rv = wv * (traj[i].v - targets[i].v);
1039 c_tracking += rx * rx + ry * ry + rth * rth + rv * rv;
1044 if (opts.use_robot_pose_proximity &&
static_cast<int>(targets.size()) == N)
1046 auto c2r = [](
const CenterPoint&
c,
double& rx,
double& ry)
1048 double ccos = std::cos(
c.theta), csin = std::sin(
c.theta);
1049 rx =
c.x + ccos * (-0.5) - csin * (0.0);
1050 ry =
c.y + csin * (-0.5) + ccos * (0.0);
1052 const double eps_sq = opts.robot_pose_proximity_eps_mm
1053 * opts.robot_pose_proximity_eps_mm;
1054 for (
int i = 1; i <= N - 2; ++i)
1056 double rx0, ry0, rx, ry;
1057 c2r(targets[i], rx0, ry0);
1058 c2r(traj[i], rx, ry);
1059 const double dx = rx - rx0;
1060 const double dy = ry - ry0;
1061 const double dist = std::hypot(dx, dy);
1062 const double y = dist - opts.robot_pose_proximity_threshold_mm;
1063 const double r = opts.w_robot_pose_proximity * tracking_scales[i] * 0.5
1064 * (std::sqrt(y * y + eps_sq) + y);
1065 c_robot_pose_proximity += r * r;
1069 double total = c_obs + c_mid_obs + c_pose_smooth + c_start_rot + c_vel_smooth + c_jerk
1070 + c_robot_smooth + c_spacing + c_tracking + c_robot_pose_proximity;
1073 auto pct = [&](
double c) ->
double {
return total > 0.0 ?
c / total * 100.0 : 0.0; };
1074 ARMARX_INFO <<
"Obstacle (waypoint): " << std::scientific << std::setprecision(3)
1075 << c_obs <<
" (" << std::fixed << std::setprecision(1) << pct(c_obs) <<
"%)";
1076 ARMARX_INFO <<
"Obstacle (midpoint): " << std::scientific << std::setprecision(3)
1077 << c_mid_obs <<
" (" << std::fixed << std::setprecision(1) << pct(c_mid_obs)
1079 ARMARX_INFO <<
"Pose smoothness: " << std::scientific << std::setprecision(3)
1080 << c_pose_smooth <<
" (" << std::fixed << std::setprecision(1)
1081 << pct(c_pose_smooth) <<
"%)";
1082 ARMARX_INFO <<
"Start/end rotation: " << std::scientific << std::setprecision(3)
1083 << c_start_rot <<
" (" << std::fixed << std::setprecision(1)
1084 << pct(c_start_rot) <<
"%)";
1085 ARMARX_INFO <<
"Velocity smoothness: " << std::scientific << std::setprecision(3)
1086 << c_vel_smooth <<
" (" << std::fixed << std::setprecision(1)
1087 << pct(c_vel_smooth) <<
"%)";
1088 ARMARX_INFO <<
"Pose jerk: " << std::scientific << std::setprecision(3)
1089 << c_jerk <<
" (" << std::fixed << std::setprecision(1) << pct(c_jerk)
1091 ARMARX_INFO <<
"Robot smoothness: " << std::scientific << std::setprecision(3)
1092 << c_robot_smooth <<
" (" << std::fixed << std::setprecision(1)
1093 << pct(c_robot_smooth) <<
"%)";
1094 ARMARX_INFO <<
"Spacing: " << std::scientific << std::setprecision(3)
1095 << c_spacing <<
" (" << std::fixed << std::setprecision(1) << pct(c_spacing)
1097 ARMARX_INFO <<
"Tracking: " << std::scientific << std::setprecision(3)
1098 << c_tracking <<
" (" << std::fixed << std::setprecision(1)
1099 << pct(c_tracking) <<
"%)";
1100 ARMARX_INFO <<
"Robot-pose proximity: " << std::scientific << std::setprecision(3)
1101 << c_robot_pose_proximity <<
" (" << std::fixed << std::setprecision(1)
1102 << pct(c_robot_pose_proximity) <<
"%)";
1103 ARMARX_INFO <<
"TOTAL: " << std::scientific << std::setprecision(3)
1113 const std::vector<CenterPoint>& traj_targets,
1116 const int N =
static_cast<int>(traj.size());
1119 ARMARX_INFO <<
"[optimizeTrajectoryCeres] need at least 4 points\n";
1123 normalizeTrajectoryAngles(traj);
1128 for (
int i = 1; i < N - 1; ++i)
1130 double dx = traj[i].x - traj[i - 1].x;
1131 double dy = traj[i].y - traj[i - 1].y;
1132 if (std::hypot(dx, dy) < 1.0)
1134 double ndx = (i + 1 < N) ? (traj[i + 1].
x - traj[i].
x) : 1.0;
1135 double ndy = (i + 1 < N) ? (traj[i + 1].y - traj[i].y) : 0.0;
1136 double nlen = std::hypot(ndx, ndy);
1143 traj[i].x += 1.0 * ndx / nlen;
1144 traj[i].y += 1.0 * ndy / nlen;
1152 std::vector<double> tracking_scales(N, 1.0);
1156 for (
int i = 0; i < N; ++i)
1159 costmap_wrapper(&traj_targets[i].
x,
1161 &traj_targets[i].theta,
1173 std::vector<bool> freeze_pose(N,
false);
1176 for (
int i = 1; i <= N - 2; ++i)
1179 costmap_wrapper(&traj_targets[i].
x,
1181 &traj_targets[i].theta,
1186 std::string frozen_indices;
1187 for (
int i = 1; i <= N - 2; ++i)
1191 if (!frozen_indices.empty())
1192 frozen_indices +=
", ";
1193 frozen_indices += std::to_string(i);
1196 ARMARX_INFO <<
"[Pass 1] Frozen waypoints (clearance <= "
1198 << (frozen_indices.empty() ?
"none" : frozen_indices) <<
"]";
1203 ceres::Problem problem;
1204 for (
int i = 0; i < N; ++i)
1205 problem.AddParameterBlock(&traj[i].x, 4);
1208 problem.SetParameterBlockConstant(&traj.front().x);
1209 problem.SetParameterBlockConstant(&traj.back().x);
1213 for (
int i = 1; i < N - 1; ++i)
1217 problem.SetParameterBlockConstant(&traj[i].
x);
1221 std::vector<int> constant_v = {3};
1227 for (
int i = 1; i <= N - 2; ++i)
1229 problem.AddResidualBlock(
1230 new ceres::AutoDiffCostFunction<PoseSmoothResidual, 3, 4, 4, 4>(
1239 problem.AddResidualBlock(
1240 new ceres::AutoDiffCostFunction<StartRotationResidual, 1, 4, 4>(
1245 problem.AddResidualBlock(
1246 new ceres::AutoDiffCostFunction<StartRotationResidual, 1, 4, 4>(
1255 for (
int i = 2; i <= N - 2; ++i)
1257 problem.AddResidualBlock(
1258 new ceres::AutoDiffCostFunction<PoseJerkResidual, 3, 4, 4, 4, 4>(
1271 for (
int i = 1; i <= N - 2; ++i)
1273 problem.AddResidualBlock(
1274 new ceres::AutoDiffCostFunction<RobotSmoothResidual, 3, 4, 4, 4>(
1284 double d_avg = computeAverageSpacing(traj);
1287 for (
int i = 0; i < N - 1; ++i)
1291 problem.AddResidualBlock(
1292 new ceres::AutoDiffCostFunction<SoftSpacingResidual, 1, 4, 4>(
1303 problem.AddResidualBlock(
1304 new ceres::AutoDiffCostFunction<SpacingResidual, 1, 4, 4>(
1315 for (
int i = 0; i < N; ++i)
1317 problem.AddResidualBlock(
1318 new ceres::AutoDiffCostFunction<ObstacleResidual, 1, 4>(
1331 for (
int i = 0; i < N - 1; ++i)
1333 problem.AddResidualBlock(
1334 new ceres::AutoDiffCostFunction<MidpointObstacleResidual, 1, 4, 4>(
1351 for (
int i = 1; i <= N - 2; ++i)
1353 problem.AddResidualBlock(
1354 new ceres::AutoDiffCostFunction<ThetaTrackingResidual, 1, 4>(
1356 traj_targets[i].theta)),
1364 if (
static_cast<int>(traj_targets.size()) != N)
1366 ARMARX_INFO <<
"[Pass 1] traj_targets size mismatch; skipping tracking.\n";
1370 for (
int i = 0; i < N; ++i)
1372 double wx = opts.
w_track * tracking_scales[i];
1373 double wy = opts.
w_track * tracking_scales[i];
1374 double wth = opts.
w_track * 300.0 * tracking_scales[i];
1375 double wv = opts.
w_track * 0.2 * tracking_scales[i];
1376 problem.AddResidualBlock(
1377 new ceres::AutoDiffCostFunction<TrackingResidual, 4, 4>(
1380 traj_targets[i].theta,
1395 if (
static_cast<int>(traj_targets.size()) != N)
1397 ARMARX_INFO <<
"[Pass 1] traj_targets size mismatch; skipping robot-pose proximity.\n";
1401 for (
int i = 1; i <= N - 2; ++i)
1403 const double cth = traj_targets[i].theta;
1404 const double rx0 = traj_targets[i].x + std::cos(cth) * (-0.5);
1405 const double ry0 = traj_targets[i].y + std::sin(cth) * (-0.5);
1407 problem.AddResidualBlock(
1408 new ceres::AutoDiffCostFunction<RobotPoseProximityResidual, 1, 4>(
1413 * tracking_scales[i],
1422 ceres::Solver::Options options;
1424 options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
1425 options.minimizer_progress_to_stdout =
false;
1427 options.function_tolerance = 1e-6;
1428 options.parameter_tolerance = 1e-8;
1429 options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
1433 options.min_relative_decrease = 1e-3;
1437 for (
int i = 0; i < N; ++i)
1443 <<
"] before solve: x=" << traj[i].x <<
" y=" << traj[i].y
1444 <<
" theta=" << traj[i].theta <<
" v=" << traj[i].v;
1450 ARMARX_WARNING <<
"[Pass 1] Pre-solve validation FAILED. Aborting.";
1454 ARMARX_INFO <<
"[Pass 1] Pre-solve residual breakdown:";
1455 logResidualBreakdown(traj, costmap_wrapper, traj_targets, tracking_scales, opts);
1457 ceres::Solver::Summary summary;
1458 ceres::Solve(options, &problem, &summary);
1459 normalizeTrajectoryAngles(traj);
1461 ARMARX_INFO <<
"[Pass 1] Post-solve residual breakdown:";
1462 logResidualBreakdown(traj, costmap_wrapper, traj_targets, tracking_scales, opts);
1464 bool postSolveValid =
true;
1465 for (
int i = 0; i < N; ++i)
1471 <<
"] AFTER solve. Reverting to pre-processed trajectory.";
1472 postSolveValid =
false;
1475 if (!postSolveValid)
1477 for (
int i = 0; i < N; ++i)
1478 traj[i] = traj_targets[i];
1479 ARMARX_WARNING <<
"[Pass 1] Trajectory reverted to pre-processed safe path.";
1484 ARMARX_INFO <<
"[Pass 1] Done. Final cost: " << summary.final_cost
1485 <<
" iterations: " << summary.num_successful_steps <<
"\n";
1491 double v_nominal = (N >= 3) ? traj[1].v : traj.front().v;
1497 std::vector<double> dangers(N);
1498 for (
int i = 0; i < N; ++i)
1501 costmap_wrapper(&traj[i].
x, &traj[i].y, &traj[i].theta, &d);
1502 dangers[i] = std::clamp(
1506 ceres::Problem problem;
1507 for (
int i = 0; i < N; ++i)
1509 problem.AddParameterBlock(&traj[i].
x, 4);
1511 std::vector<int> constant_indices = {0, 1, 2};
1517 problem.SetParameterBlockConstant(&traj.front().x);
1518 problem.SetParameterBlockConstant(&traj.back().x);
1521 for (
int i = 0; i < N - 1; ++i)
1523 problem.AddResidualBlock(
1524 new ceres::AutoDiffCostFunction<AccelDecelLimitResidual, 1, 4, 4>(
1534 for (
int i = 1; i < N - 1; ++i)
1536 problem.AddResidualBlock(
1537 new ceres::AutoDiffCostFunction<NominalVelocityResidual, 1, 4>(
1544 for (
int i = 1; i < N - 1; ++i)
1546 problem.AddResidualBlock(
1547 new ceres::AutoDiffCostFunction<VelocityProximityResidual, 1, 4>(
1556 ceres::Solver::Options options;
1558 options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
1559 options.minimizer_progress_to_stdout =
false;
1561 options.function_tolerance = 1e-6;
1562 options.parameter_tolerance = 1e-8;
1563 options.trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT;
1567 options.min_relative_decrease = 1e-3;
1569 ceres::Solver::Summary summary;
1570 ceres::Solve(options, &problem, &summary);
1573 ARMARX_INFO <<
"[Pass 2] Done. Final cost: " << summary.final_cost
1574 <<
" iterations: " << summary.num_successful_steps <<
"\n";
1577 normalizeTrajectoryAngles(traj);
Brief description of class targets.
#define ARMARX_INFO
The normal logging level.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
double s(double t, double s0, double v0, double a0, double j)
double v(double t, double v0, double a0, double j)
T expForSmoothMin(const T &x)
T logForSmoothMin(const T &x)
This file is part of ArmarX.
void optimizeTrajectoryCeres(std::vector< CenterPoint > &traj, const Costmap3DWrapper &costmap_wrapper, const std::vector< CenterPoint > &traj_targets, const io::SmoothingParams &opts)
double smoothstep(double edge0, double edge1, double x)
double normalizeAngle(double a)
T angleDiff(const T &a, const T &b)
T smoothMin(const std::vector< T > &values, double alpha)
double trackingScaleFromClearance(double clearance, double fade_start_clearance, double fade_end_clearance)
This file offers overloads of toIce() and fromIce() functions for STL container types.
bool isfinite(const std::vector< T, Ts... > &v)
ceres::SubsetParameterization SubsetConstraint
This file is part of ArmarX.
#define SET_CONSTRAINT(problem, param, constraint)
AccelDecelLimitResidual(double max_accel, double max_decel, double weight)
bool operator()(const T *const c_i, const T *const c_ip1, T *residual) const
MidpointObstacleResidual(const Costmap3DWrapper &wrapper, double weight, double max_dist, double clearance, double barrier_eps, bool use_fuzzy_orientation=true, int num_orientations=72, int fuzzy_window_bins=2, double fuzzy_alpha=5.0)
const Costmap3DWrapper & wrapper_
bool operator()(const T *const c_i, const T *const c_ip1, T *residual) const
bool use_fuzzy_orientation_
NominalVelocityResidual(double v_nominal, double weight)
bool operator()(const T *const c_i, T *residual) const
const Costmap3DWrapper & wrapper_
ObstacleResidual(const Costmap3DWrapper &wrapper, double weight, double max_dist, double clearance, double barrier_eps, bool use_fuzzy_orientation=true, int num_orientations=72, int fuzzy_window_bins=2, double fuzzy_alpha=5.0)
bool operator()(const T *const node, T *residual) const
bool use_fuzzy_orientation_
bool operator()(const T *const c_m2, const T *const c_m1, const T *const c_i, const T *const c_p1, T *residual) const
PoseJerkResidual(double weight=1.0)
PoseSmoothResidual(double pos_weight=1.0, double orientation_weight=1.0)
bool operator()(const T *const c_prev, const T *const c_i, const T *const c_next, T *residual) const
void centerToRobot(const T *const c, T &rx, T &ry) const
RobotPoseProximityResidual(double rx0, double ry0, double threshold_mm, double weight, double eps_mm)
bool operator()(const T *const c_i, T *residual) const
bool operator()(const T *const c_prev, const T *const c_i, const T *const c_next, T *residual) const
RobotSmoothResidual(double weight=1.0, double dx=-0.5, double dy=0.0)
void centerToRobotTemplated(const T *const c, T &rx, T &ry, T &rtheta) const
bool operator()(const T *const c_i, const T *const c_ip1, T *residual) const
SoftSpacingResidual(double d_avg, double linear_weight, double quadratic_weight, double relative_deviation_threshold)
SpacingResidual(double d_avg, double weight)
bool operator()(const T *const c_i, const T *const c_ip1, T *residual) const
StartRotationResidual(double w)
bool operator()(const T *const theta0, const T *const theta1, T *residuals) const
ThetaTrackingResidual(double w, double theta_target)
bool operator()(const T *const node, T *residual) const
TrackingResidual(double xr, double yr, double thetar, double vr, double wx, double wy, double wth, double wv)
bool operator()(const T *const c_i, T *residual) const
VelLimitResidual(double vmax, double weight=1.0)
bool operator()(const T *const c_i, T *residual) const
VelocityProximityResidual(double danger, double min_velocity, double weight)
bool operator()(const T *const c_i, T *residual) const
double fuzzy_orientation_alpha
bool use_fuzzy_orientation
double slow_down_distance
int fuzzy_orientation_window_bins
double obs_barrier_eps_mm
double tracking_fade_end_clearance
double min_velocity_near_obstacle
double max_decel_per_segment
double w_orientation_smooth
double w_nominal_velocity
double max_trust_region_radius
double spacing_relative_deviation_threshold
double robot_pose_proximity_threshold_mm
double w_accel_decel_limit
bool use_robot_pose_proximity
double w_velocity_proximity
double tracking_fade_start_clearance
bool use_tracking_clearance_adaptive
double robot_pose_proximity_eps_mm
double w_spacing_quadratic
double w_robot_pose_proximity
double max_accel_per_segment
double obstacle_freeze_threshold
double initial_trust_region_radius
double min_trust_region_radius