25#include "absl/strings/str_cat.h"
44using Matrix = Eigen::MatrixXd;
49std::string GetLogFileName() {
54 localtime_r(&raw_time, &time_tm);
55 strftime(name_buffer, 80,
"/tmp/steer_log_simple_optimal_%F_%H%M%S.csv",
57 return std::string(name_buffer);
60void WriteHeaders(std::ofstream &file_stream) {
61 file_stream <<
"current_lateral_error," <<
"current_ref_heading,"
62 <<
"current_heading," <<
"current_heading_error,"
63 <<
"heading_error_rate," <<
"lateral_error_rate,"
64 <<
"current_curvature," <<
"steer_angle,"
65 <<
"steer_angle_feedforward,"
66 <<
"steer_angle_lateral_contribution,"
67 <<
"steer_angle_lateral_rate_contribution,"
68 <<
"steer_angle_heading_contribution,"
69 <<
"steer_angle_heading_rate_contribution,"
70 <<
"steer_angle_feedback," <<
"steering_position," <<
"v"
76 if (FLAGS_enable_csv_debug) {
89 common::VehicleConfigHelper::Instance()->GetConfig().vehicle_param();
93 AERROR <<
"[LatController] Invalid control update interval.";
119 const double mass_front = mass_fl + mass_fr;
120 const double mass_rear = mass_rl + mass_rr;
121 mass_ = mass_front + mass_rear;
141 const std::string log_str = absl::StrCat(
151 injector_->vehicle_state()->linear_velocity());
152 if (FLAGS_enable_csv_debug) {
155 ADEBUG <<
"Steer_Control_Detail: " << log_str;
160 AINFO <<
"[LatController parameters]" <<
" mass_: " <<
mass_ <<
","
161 <<
" iz_: " <<
iz_ <<
"," <<
" lf_: " <<
lf_ <<
"," <<
" lr_: " <<
lr_;
166 std::vector<double> den(3, 0.0);
167 std::vector<double> num(3, 0.0);
178 if (!ControlTask::LoadConfig<LatBaseLqrControllerConf>(
180 AERROR <<
"failed to load control conf";
181 return Status(ErrorCode::CONTROL_INIT_ERROR,
182 "failed to load lat control_conf");
186 AERROR <<
"failed to load control conf";
187 return Status(ErrorCode::CONTROL_COMPUTE_ERROR,
188 "failed to load control_conf");
194 matrix_adc_ = Matrix::Zero(matrix_size, matrix_size);
226 matrix_k_ = Matrix::Zero(1, matrix_size);
228 matrix_q_ = Matrix::Zero(matrix_size, matrix_size);
231 int reverse_q_param_size =
233 if (matrix_size != q_param_size || matrix_size != reverse_q_param_size) {
234 const auto error_msg = absl::StrCat(
235 "lateral controller error: matrix_q size: ", q_param_size,
236 "lateral controller error: reverse_matrix_q size: ",
237 reverse_q_param_size,
238 " in parameter file not equal to matrix_size: ", matrix_size);
240 return Status(ErrorCode::CONTROL_COMPUTE_ERROR, error_msg);
243 for (
int i = 0; i < q_param_size; ++i) {
278 const auto &lat_err_gain_scheduler =
280 const auto &heading_err_gain_scheduler =
282 AINFO <<
"Lateral control gain scheduler loaded";
284 for (
const auto &scheduler : lat_err_gain_scheduler.scheduler()) {
285 xy1.push_back(std::make_pair(scheduler.speed(), scheduler.ratio()));
287 for (
const auto &scheduler : heading_err_gain_scheduler.scheduler()) {
288 xy2.push_back(std::make_pair(scheduler.speed(), scheduler.ratio()));
293 <<
"Fail to load lateral error gain scheduler";
297 <<
"Fail to load heading error gain scheduler";
309 auto vehicle_state =
injector_->vehicle_state();
310 auto previous_lon_debug =
injector_->Get_previous_lon_debug_info();
311 auto target_tracking_trajectory = *planning_published_trajectory;
313 if (FLAGS_use_navigation_mode &&
315 auto time_stamp_diff =
322 double curr_vehicle_heading = 0.0;
324 if (localization->
pose().has_heading()) {
325 curr_vehicle_heading = localization->
pose().
heading();
327 curr_vehicle_heading =
329 orientation.qy(), orientation.qz());
333 if (time_stamp_diff > 1.0e-6) {
348 auto x_diff_veh = cos_map_veh * x_diff_map + sin_map_veh * y_diff_map;
349 auto y_diff_veh = -sin_map_veh * x_diff_map + cos_map_veh * y_diff_map;
351 auto cos_theta_diff = std::cos(-theta_diff);
352 auto sin_theta_diff = std::sin(-theta_diff);
354 auto tx = -(cos_theta_diff * x_diff_veh - sin_theta_diff * y_diff_veh);
355 auto ty = -(sin_theta_diff * x_diff_veh + cos_theta_diff * y_diff_veh);
357 auto ptr_trajectory_points =
358 target_tracking_trajectory.mutable_trajectory_point();
360 ptr_trajectory_points->begin(), ptr_trajectory_points->end(),
361 [&cos_theta_diff, &sin_theta_diff, &tx, &ty,
363 auto x = p.path_point().x();
364 auto y = p.path_point().y();
365 auto theta = p.path_point().theta();
367 auto x_new = cos_theta_diff * x - sin_theta_diff * y + tx;
368 auto y_new = sin_theta_diff * x + cos_theta_diff * y + ty;
369 auto theta_new = common::math::NormalizeAngle(theta - theta_diff);
371 p.mutable_path_point()->set_x(x_new);
372 p.mutable_path_point()->set_y(y_new);
373 p.mutable_path_point()->set_theta(theta_new);
453 int reverse_q_param_size =
456 for (
int i = 0; i < reverse_q_param_size; ++i) {
460 for (
int i = 0; i < q_param_size; ++i) {
468 if (FLAGS_enable_gain_scheduler) {
471 std::fabs(vehicle_state->linear_velocity()));
474 std::fabs(vehicle_state->linear_velocity()));
477 &
matrix_k_, &num_iteration, &result_diff);
481 &
matrix_k_, &num_iteration, &result_diff);
484 ADEBUG <<
"LQR num_iteration is " << num_iteration
486 <<
"; result_diff is " << result_diff;
497 double steer_angle = 0.0;
498 double steer_angle_feedback_augment = 0.0;
502 .enable_feedback_augment_on_high_speed() ||
504 steer_angle_feedback_augment =
507 if (std::fabs(vehicle_state->linear_velocity()) >
517 steer_angle = steer_angle_feedback + steer_angle_feedforward +
518 steer_angle_feedback_augment;
522 const double steer_limit =
524 (vehicle_state->linear_velocity() *
525 vehicle_state->linear_velocity())) *
530 const double steer_diff_with_max_rate =
541 const int mrac_model_order =
543 Matrix steer_state = Matrix::Zero(mrac_model_order, 1);
545 if (mrac_model_order > 1) {
548 if (std::fabs(vehicle_state->linear_velocity()) >
549 FLAGS_minimum_speed_resolution) {
557 steer_angle, steer_state, steer_limit, steer_diff_with_max_rate /
ts_);
559 MracDebug *mracdebug = debug->mutable_steer_mrac_debug();
561 mracdebug->set_mrac_model_order(mrac_model_order);
562 for (
int i = 0; i < mrac_model_order; ++i) {
563 mracdebug->add_mrac_reference_state(steer_reference(i, 0));
564 mracdebug->add_mrac_state_error(steer_state(i, 0) -
565 steer_reference(i, 0));
566 mracdebug->mutable_mrac_adaptive_gain()->add_state_adaptive_gain(
569 mracdebug->mutable_mrac_adaptive_gain()->add_input_adaptive_gain(
571 mracdebug->set_mrac_reference_saturation_status(
573 mracdebug->set_mrac_control_saturation_status(
580 double steer_angle_limited =
582 steer_angle = steer_angle_limited;
583 debug->set_steer_angle_limited(steer_angle_limited);
592 if ((std::abs(vehicle_state->linear_velocity()) <
594 previous_lon_debug->path_remain() <= 0) &&
597 ADEBUG <<
"Into lock steer, path_remain is "
598 << previous_lon_debug->path_remain() <<
"linear_velocity is "
599 << vehicle_state->linear_velocity();
608 cmd->set_steering_rate(FLAGS_steer_angle_rate);
613 const double steer_angle_lateral_contribution =
617 const double steer_angle_lateral_rate_contribution =
621 const double steer_angle_heading_contribution =
625 const double steer_angle_heading_rate_contribution =
630 debug->set_steer_angle(steer_angle);
631 debug->set_steer_angle_feedforward(steer_angle_feedforward);
632 debug->set_steer_angle_lateral_contribution(steer_angle_lateral_contribution);
633 debug->set_steer_angle_lateral_rate_contribution(
634 steer_angle_lateral_rate_contribution);
635 debug->set_steer_angle_heading_contribution(steer_angle_heading_contribution);
636 debug->set_steer_angle_heading_rate_contribution(
637 steer_angle_heading_rate_contribution);
638 debug->set_steer_angle_feedback(steer_angle_feedback);
639 debug->set_steer_angle_feedback_augment(steer_angle_feedback_augment);
640 debug->set_steering_position(steering_position);
641 debug->set_ref_speed(vehicle_state->linear_velocity());
657 auto vehicle_state =
injector_->vehicle_state();
658 if (FLAGS_use_navigation_mode) {
661 vehicle_state->angular_velocity(), vehicle_state->linear_acceleration(),
666 const auto &com = vehicle_state->ComputeCOMPosition(
lr_);
668 vehicle_state->linear_velocity(),
669 vehicle_state->angular_velocity(),
670 vehicle_state->linear_acceleration(),
688 const double preview_time =
ts_ * (i + 1);
689 const auto preview_point =
693 preview_point.path_point().x(), preview_point.path_point().y());
696 preview_point.
path_point().
x() - matched_point.path_point().x();
698 preview_point.path_point().y() - matched_point.path_point().y();
700 const double cos_matched_theta =
701 std::cos(matched_point.path_point().theta());
702 const double sin_matched_theta =
703 std::sin(matched_point.path_point().theta());
704 const double preview_d_error =
705 cos_matched_theta * dy - sin_matched_theta * dx;
717 v = std::min(
injector_->vehicle_state()->linear_velocity(),
721 v = std::max(
injector_->vehicle_state()->linear_velocity(),
753 const double v =
injector_->vehicle_state()->linear_velocity();
754 double steer_angle_feedforwardterm;
757 steer_angle_feedforwardterm =
762 steer_angle_feedforwardterm =
763 (
wheelbase_ * ref_curvature + kv * v * v * ref_curvature -
765 (
lr_ * ref_curvature -
770 return steer_angle_feedforwardterm;
774 const double x,
const double y,
const double theta,
const double linear_v,
775 const double angular_v,
const double linear_a,
784 if (FLAGS_use_navigation_mode &&
786 .enable_navigation_mode_position_update()) {
793 const double dx = x - target_point.
path_point().
x();
794 const double dy = y - target_point.
path_point().
y();
796 debug->mutable_current_target_point()->mutable_path_point()->set_x(
798 debug->mutable_current_target_point()->mutable_path_point()->set_y(
801 ADEBUG <<
"x point: " << x <<
" y point: " << y;
802 ADEBUG <<
"match point information : " << target_point.ShortDebugString();
804 const double cos_target_heading = std::cos(target_point.
path_point().
theta());
805 const double sin_target_heading = std::sin(target_point.
path_point().
theta());
807 double lateral_error = cos_target_heading * dy - sin_target_heading * dx;
812 debug->set_lateral_error(lateral_error);
815 double heading_error =
820 debug->set_heading_error(heading_error);
824 double lookahead_station = 0.0;
825 double lookback_station = 0.0;
843 double heading_error_feedback;
845 heading_error_feedback = heading_error;
850 (std::max(std::fabs(linear_v), 0.1) * std::cos(heading_error)));
853 lookahead_point.path_point().theta());
855 debug->set_heading_error_feedback(heading_error_feedback);
859 double lateral_error_feedback;
861 lateral_error_feedback =
862 lateral_error - lookback_station * std::sin(heading_error);
864 lateral_error_feedback =
865 lateral_error + lookahead_station * std::sin(heading_error);
867 debug->set_lateral_error_feedback(lateral_error_feedback);
869 auto lateral_error_dot = linear_v * std::sin(heading_error);
870 auto lateral_error_dot_dot = linear_a * std::sin(heading_error);
871 if (FLAGS_reverse_heading_control) {
873 lateral_error_dot = -lateral_error_dot;
874 lateral_error_dot_dot = -lateral_error_dot_dot;
877 auto centripetal_acceleration =
881 debug->set_lateral_error_rate(lateral_error_dot);
882 debug->set_lateral_acceleration(lateral_error_dot_dot);
883 debug->set_lateral_centripetal_acceleration(centripetal_acceleration);
884 debug->set_lateral_jerk(
889 debug->set_heading_rate(-angular_v);
891 debug->set_heading_rate(angular_v);
898 debug->set_heading_acceleration(
900 debug->set_ref_heading_acceleration(
907 debug->set_heading_jerk(
909 debug->set_ref_heading_jerk(
921 auto vehicle_state =
injector_->vehicle_state();
925 if (FLAGS_reverse_heading_control) {
931 ADEBUG <<
"Matrix_b changed due to gear direction";
void set_coefficients(const std::vector< double > &denominators, const std::vector< double > &numerators)
set denominators and numerators
double Filter(const double x_insert)
Processes a new measurement with the filter.
The MeanFilter class is used to smoothen a series of noisy numbers, such as sensor data or the output...
double Update(const double measurement)
Processes a new measurement in amortized constant time.
A general class to denote the return status of an API call.
static Status OK()
generate a success status.
The class of vehicle state.
std::vector< std::pair< double, double > > DataType
Eigen::MatrixXd matrix_a_coeff_
void UpdateMatrixCompound()
double current_trajectory_timestamp_
void LoadLatGainScheduler()
double lookahead_station_low_speed_
Eigen::MatrixXd matrix_bdc_
double ComputeFeedForward(double ref_curvature) const
double lookback_station_high_speed_
std::ofstream steer_log_file_
double lookahead_station_high_speed_
double query_relative_time_
double lookback_station_low_speed_
MracController mrac_controller_
TrajectoryAnalyzer trajectory_analyzer_
common::MeanFilter lateral_error_filter_
double minimum_speed_protection_
double previous_heading_rate_
void Stop() override
stop Lateral controller
void UpdateState(SimpleLateralDebug *debug, const canbus::Chassis *chassis)
double previous_ref_heading_acceleration_
Eigen::MatrixXd matrix_adc_
double pre_steering_position_
virtual ~LatController()
destructor
Eigen::MatrixXd matrix_a_
void ProcessLogs(const SimpleLateralDebug *debug, const canbus::Chassis *chassis)
Eigen::MatrixXd matrix_b_
common::MeanFilter heading_error_filter_
Eigen::MatrixXd matrix_k_
Eigen::MatrixXd matrix_ad_
void UpdateDrivingOrientation()
Eigen::MatrixXd matrix_q_
void ComputeLateralErrors(const double x, const double y, const double theta, const double linear_v, const double angular_v, const double linear_a, const TrajectoryAnalyzer &trajectory_analyzer, SimpleLateralDebug *debug, const canbus::Chassis *chassis)
common::Status Init(std::shared_ptr< DependencyInjector > injector) override
initialize Lateral Controller
double steer_single_direction_max_degree_
double driving_orientation_
const int basic_state_size_
common::Status Reset() override
reset Lateral Controller
common::DigitalFilter digital_filter_
LatBaseLqrControllerConf lat_based_lqr_controller_conf_
bool enable_look_ahead_back_control_
LatController()
constructor
std::string Name() const override
Lateral controller name
std::unique_ptr< Interpolation1D > heading_err_interpolation_
Eigen::MatrixXd matrix_state_
double previous_lateral_acceleration_
std::shared_ptr< DependencyInjector > injector_
Eigen::MatrixXd matrix_q_updated_
LeadlagController leadlag_controller_
common::Status ComputeControlCommand(const localization::LocalizationEstimate *localization, const canbus::Chassis *chassis, const planning::ADCTrajectory *trajectory, ControlCommand *cmd) override
compute steering target based on current vehicle status and target trajectory
std::unique_ptr< Interpolation1D > lat_err_interpolation_
double init_vehicle_heading_
double previous_ref_heading_rate_
common::VehicleParam vehicle_param_
Eigen::MatrixXd matrix_r_
Eigen::MatrixXd matrix_bd_
double previous_heading_acceleration_
void Init(const LeadlagConf &leadlag_conf, const double dt)
initialize lead/lag controller
virtual double Control(const double error, const double dt)
compute control value based on the error
void SetInputAdaptionRate(const double ratio_input)
set convergence ratio for input components in adaptive dynamics
Eigen::MatrixXd CurrentInputAdaptionGain() const
get current input adaptive gain for mrac control
virtual double Control(const double command, const Eigen::MatrixXd state, const double input_limit, const double input_rate_limit)
compute control value based on the original command
void Init(const MracConf &mrac_conf, const common::LatencyParam &latency_param, const double dt)
initialize mrac controller
int ReferenceSaturationStatus() const
get saturation status for reference system
void Reset()
reset all the variables (including all the states, gains and externally-setting control parameters) f...
int ControlSaturationStatus() const
get saturation status for control system
void SetStateAdaptionRate(const double ratio_state)
set convergence ratio for state components in adaptive dynamics
Eigen::MatrixXd CurrentReferenceState() const
get current state for reference system
Eigen::MatrixXd CurrentStateAdaptionGain() const
get current state adaptive gain for mrac control
process point query and conversion related to trajectory
common::TrajectoryPoint QueryNearestPointByPosition(const double x, const double y) const
query a point of trajectory that its position is closest to the given position.
void TrajectoryTransformToCOM(const double rear_to_com_distance)
Transform the current trajectory points to the center of mass(COM) of the vehicle,...
common::TrajectoryPoint QueryNearestPointByAbsoluteTime(const double t) const
query a point of trajectory that its absolute time is closest to the give time.
common::TrajectoryPoint QueryNearestPointByRelativeTime(const double t) const
query a point of trajectory that its relative time is closest to the give time.
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
Math-related util functions.
Defines the LatController class.
Linear interpolation functions.
Solver for discrete-time linear quadratic problem.
T lerp(const T &x0, const double t0, const T &x1, const double t1, const double t)
Linear interpolation between two points of type T.
void SolveLQRProblem(const Matrix &A, const Matrix &B, const Matrix &Q, const Matrix &R, const Matrix &M, const double tolerance, const uint max_num_iteration, Matrix *ptr_K, uint *iterate_num, double *result_diff)
T Clamp(const T value, T bound1, T bound2)
Clamp a value between two bounds.
double QuaternionToHeading(const double qw, const double qx, const double qy, const double qz)
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
void LpfCoefficients(const double ts, const double cutoff_freq, std::vector< double > *denominators, std::vector< double > *numerators)
Get low-pass coefficients for digital filter.
Contains a number of helper functions related to quaternions.
optional DrivingMode driving_mode
optional float steering_percentage
optional double relative_time
optional PathPoint path_point
optional double max_steer_angle
optional LatencyParam steering_latency_param
optional double steer_ratio
optional double max_steer_angle_rate
optional double wheel_base
optional double steering_target
optional double steer_angle_lateral_rate_contribution
optional double heading_rate
optional double steer_angle_feedforward
optional double steer_angle
optional double heading_error_feedback
optional double steer_angle_heading_rate_contribution
optional double lateral_error
optional double ref_heading_rate
optional double steer_angle_lateral_contribution
optional double lateral_error_feedback
optional double heading_error_rate
optional double ref_heading_jerk
optional double lateral_acceleration
optional double ref_heading_acceleration
optional double steer_angle_feedback
optional double steer_angle_heading_contribution
optional double lateral_error_rate
optional double heading_jerk
optional double ref_heading
optional double heading_error
optional double heading_acceleration
optional double curvature
optional apollo::localization::Pose pose
optional apollo::common::Quaternion orientation
optional apollo::common::PointENU position
optional apollo::common::Header header