概述
TrajectoryStitcher类是apollo planning模块下modules\planning\common\trajectory_stitcher.cc/.h实现
从类名来看,应该是轨迹缝合类?
从代码来看TrajectoryStitcher类主要是实现: 1.触发轨迹重规划replan时以车辆当前状态/运动学递推0.1s后的状态作为下一段规划起始点;replan时返回的轨迹只有一个起始点? 2.没触发规划轨迹replan时,进行规划轨迹缝合,截取缝合轨迹起点以车辆当前状态在上一帧规划轨迹匹配点(时间,距离匹配点中较小的一个)往回退20个点,截取缝合轨迹终点为到当前时间戳+0.1s在上一帧轨迹上对应点。然后将当前时间戳作为下一段规划轨迹的相对时间为0的点,将当前时间戳往后推0.1s的点对应的s作为下一段规划轨迹的纵坐标起点s=0的点,根据新的时间起点和纵坐标起点更新缝合轨迹。
简而言之,该类就是一是实现特定条件下触发轨迹重规划replan(以车辆当前状态出发进行规划);二是没有触发replan时进行轨迹缝合(其实也是依赖车辆当前状态去拼接上一帧规划轨迹和下一帧规划轨迹,在上一帧轨迹中找到车辆当前状态最接近的点并在其附近截断,下一帧规划轨迹又以车辆当前状态出发继续规划,车辆当前状态就将上一帧规划轨迹和下一帧规划轨迹连接起来了),这样规划轨迹始终是比较连续的?
*触发规划轨迹重规划replan的条件: a.关闭轨迹缝合时; b.上一帧规划轨迹为空时; c.车辆不处于完全自动驾驶时; d.上一帧规划轨迹点数量为0时; e.当前时间戳小于上一帧轨迹的起点的时间; f.当前时间戳超出了上一帧轨迹的最后一个点的时间; g.先前的轨迹无路径点; h.横向误差超过0.5m 或纵向误差超过2.5m
trajectory_stitcher.h
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "modules/common/proto/pnc_point.pb.h"
#include "modules/common/vehicle_state/proto/vehicle_state.pb.h"
#include "modules/planning/common/trajectory/publishable_trajectory.h"
#include "modules/planning/reference_line/reference_line.h"
namespace apollo {
namespace planning {
class TrajectoryStitcher {
public:
TrajectoryStitcher() = delete;
static void TransformLastPublishedTrajectory(
const double x_diff, const double y_diff, const double theta_diff,
PublishableTrajectory* prev_trajectory);
static std::vector<common::TrajectoryPoint> ComputeStitchingTrajectory(
const common::VehicleState& vehicle_state, const double current_timestamp,
const double planning_cycle_time, const size_t preserved_points_num,
const bool replan_by_offset, const PublishableTrajectory* prev_trajectory,
std::string* replan_reason);
static std::vector<common::TrajectoryPoint> ComputeReinitStitchingTrajectory(
const double planning_cycle_time,
const common::VehicleState& vehicle_state);
private:
static std::pair<double, double> ComputePositionProjection(
const double x, const double y,
const common::TrajectoryPoint& matched_trajectory_point);
static common::TrajectoryPoint ComputeTrajectoryPointFromVehicleState(
const double planning_cycle_time,
const common::VehicleState& vehicle_state);
};
}
}
trajectory_stitcher.cc
#include "modules/planning/common/trajectory_stitcher.h"
#include <algorithm>
#include "absl/strings/str_cat.h"
#include "cyber/common/log.h"
#include "modules/common/configs/config_gflags.h"
#include "modules/common/math/angle.h"
#include "modules/common/math/quaternion.h"
#include "modules/common/util/util.h"
#include "modules/common/vehicle_model/vehicle_model.h"
#include "modules/planning/common/planning_gflags.h"
namespace apollo {
namespace planning {
using apollo::common::TrajectoryPoint;
using apollo::common::VehicleModel;
using apollo::common::VehicleState;
using apollo::common::math::Vec2d;
TrajectoryPoint TrajectoryStitcher::ComputeTrajectoryPointFromVehicleState(
const double planning_cycle_time, const VehicleState& vehicle_state) {
TrajectoryPoint point;
point.mutable_path_point()->set_s(0.0);
point.mutable_path_point()->set_x(vehicle_state.x());
point.mutable_path_point()->set_y(vehicle_state.y());
point.mutable_path_point()->set_z(vehicle_state.z());
point.mutable_path_point()->set_theta(vehicle_state.heading());
point.mutable_path_point()->set_kappa(vehicle_state.kappa());
point.set_v(vehicle_state.linear_velocity());
point.set_a(vehicle_state.linear_acceleration());
point.set_relative_time(planning_cycle_time);
return point;
}
std::vector<TrajectoryPoint>
TrajectoryStitcher::ComputeReinitStitchingTrajectory(
const double planning_cycle_time, const VehicleState& vehicle_state) {
TrajectoryPoint reinit_point;
static constexpr double kEpsilon_v = 0.1;
static constexpr double kEpsilon_a = 0.4;
if (std::abs(vehicle_state.linear_velocity()) < kEpsilon_v &&
std::abs(vehicle_state.linear_acceleration()) < kEpsilon_a) {
reinit_point = ComputeTrajectoryPointFromVehicleState(planning_cycle_time,
vehicle_state);
} else {
VehicleState predicted_vehicle_state;
predicted_vehicle_state =
VehicleModel::Predict(planning_cycle_time, vehicle_state);
reinit_point = ComputeTrajectoryPointFromVehicleState(
planning_cycle_time, predicted_vehicle_state);
}
return std::vector<TrajectoryPoint>(1, reinit_point);
}
void TrajectoryStitcher::TransformLastPublishedTrajectory(
const double x_diff, const double y_diff, const double theta_diff,
PublishableTrajectory* prev_trajectory) {
if (!prev_trajectory) {
return;
}
double cos_theta = std::cos(theta_diff);
double sin_theta = -std::sin(theta_diff);
auto tx = -(cos_theta * x_diff - sin_theta * y_diff);
auto ty = -(sin_theta * x_diff + cos_theta * y_diff);
std::for_each(prev_trajectory->begin(), prev_trajectory->end(),
[&cos_theta, &sin_theta, &tx, &ty,
&theta_diff](common::TrajectoryPoint& p) {
auto x = p.path_point().x();
auto y = p.path_point().y();
auto theta = p.path_point().theta();
auto x_new = cos_theta * x - sin_theta * y + tx;
auto y_new = sin_theta * x + cos_theta * y + ty;
auto theta_new =
common::math::NormalizeAngle(theta - theta_diff);
p.mutable_path_point()->set_x(x_new);
p.mutable_path_point()->set_y(y_new);
p.mutable_path_point()->set_theta(theta_new);
});
}
std::vector<TrajectoryPoint> TrajectoryStitcher::ComputeStitchingTrajectory(
const VehicleState& vehicle_state, const double current_timestamp,
const double planning_cycle_time, const size_t preserved_points_num,
const bool replan_by_offset, const PublishableTrajectory* prev_trajectory,
std::string* replan_reason) {
if (!FLAGS_enable_trajectory_stitcher) {
*replan_reason = "stitch is disabled by gflag.";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
if (!prev_trajectory) {
*replan_reason = "replan for no previous trajectory.";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
if (vehicle_state.driving_mode() != canbus::Chassis::COMPLETE_AUTO_DRIVE) {
*replan_reason = "replan for manual mode.";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
size_t prev_trajectory_size = prev_trajectory->NumOfPoints();
if (prev_trajectory_size == 0) {
ADEBUG << "Projected trajectory at time [" << prev_trajectory->header_time()
<< "] size is zero! Previous planning not exist or failed. Use "
"origin car status instead.";
*replan_reason = "replan for empty previous trajectory.";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
const double veh_rel_time =
current_timestamp - prev_trajectory->header_time();
size_t time_matched_index =
prev_trajectory->QueryLowerBoundPoint(veh_rel_time);
if (time_matched_index == 0 &&
veh_rel_time < prev_trajectory->StartPoint().relative_time()) {
AWARN << "current time smaller than the previous trajectory's first time";
*replan_reason =
"replan for current time smaller than the previous trajectory's first "
"time.";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
if (time_matched_index + 1 >= prev_trajectory_size) {
AWARN << "current time beyond the previous trajectory's last time";
*replan_reason =
"replan for current time beyond the previous trajectory's last time";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
auto time_matched_point = prev_trajectory->TrajectoryPointAt(
static_cast<uint32_t>(time_matched_index));
if (!time_matched_point.has_path_point()) {
*replan_reason = "replan for previous trajectory missed path point";
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
size_t position_matched_index = prev_trajectory->QueryNearestPointWithBuffer(
{vehicle_state.x(), vehicle_state.y()}, 1.0e-6);
auto frenet_sd = ComputePositionProjection(
vehicle_state.x(), vehicle_state.y(),
prev_trajectory->TrajectoryPointAt(
static_cast<uint32_t>(position_matched_index)));
if (replan_by_offset) {
auto lon_diff = time_matched_point.path_point().s() - frenet_sd.first;
auto lat_diff = frenet_sd.second;
ADEBUG << "Control lateral diff: " << lat_diff
<< ", longitudinal diff: " << lon_diff;
if (std::fabs(lat_diff) > FLAGS_replan_lateral_distance_threshold) {
const std::string msg = absl::StrCat(
"the distance between matched point and actual position is too "
"large. Replan is triggered. lat_diff = ",
lat_diff);
AERROR << msg;
*replan_reason = msg;
return ComputeReinitStitchingTrajectory(planning_cycle_time,
vehicle_state);
}
if (std::fabs(lon_diff) > FLAGS_replan_longitudinal_distance_threshold) {
const std::string msg = absl::StrCat(
"the distance between matched point and actual position is too "
"large. Replan is triggered. lon_diff = ",
lon_diff);
AERROR << msg;
*replan_reason = msg;
return ComputeReinitStitchingTrajectory(planning_cycle_time,
vehicle_state);
}
} else {
ADEBUG << "replan according to certain amount of lat and lon offset is "
"disabled";
}
double forward_rel_time = veh_rel_time + planning_cycle_time;
size_t forward_time_index =
prev_trajectory->QueryLowerBoundPoint(forward_rel_time);
ADEBUG << "Position matched index:\t" << position_matched_index;
ADEBUG << "Time matched index:\t" << time_matched_index;
auto matched_index = std::min(time_matched_index, position_matched_index);
std::vector<TrajectoryPoint> stitching_trajectory(
prev_trajectory->begin() +
std::max(0, static_cast<int>(matched_index - preserved_points_num)),
prev_trajectory->begin() + forward_time_index + 1);
ADEBUG << "stitching_trajectory size: " << stitching_trajectory.size();
const double zero_s = stitching_trajectory.back().path_point().s();
for (auto& tp : stitching_trajectory) {
if (!tp.has_path_point()) {
*replan_reason = "replan for previous trajectory missed path point";
return ComputeReinitStitchingTrajectory(planning_cycle_time,
vehicle_state);
}
tp.set_relative_time(tp.relative_time() + prev_trajectory->header_time() -
current_timestamp);
tp.mutable_path_point()->set_s(tp.path_point().s() - zero_s);
}
return stitching_trajectory;
}
std::pair<double, double> TrajectoryStitcher::ComputePositionProjection(
const double x, const double y, const TrajectoryPoint& p) {
Vec2d v(x - p.path_point().x(), y - p.path_point().y());
Vec2d n(std::cos(p.path_point().theta()), std::sin(p.path_point().theta()));
std::pair<double, double> frenet_sd;
frenet_sd.first = v.InnerProd(n) + p.path_point().s();
frenet_sd.second = v.CrossProd(n);
return frenet_sd;
}
}
}
|