trajectory_optimization v1.3.1
Loading...
Searching...
No Matches
trajectory_optimization_ackermann.cpp
Go to the documentation of this file.
1// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
2// SPDX-License-Identifier: Apache-2.0
3
5
6#include <rclcpp_components/register_node_macro.hpp>
7
9
11
13 : TrajectoryOptimizationNode("TrajectoryOptimizationAckermannNode", options) {
14 this->declareAndLoadParameter("bi_level_dDelta", bi_level_dDelta_,
15 "Threshold for bi-level stabilization: maximum ackermann steering angle difference [degree]");
16}
17
18void TrajectoryOptimizationAckermannNode::initializeTrajectory(trajectory_planning_msgs::msg::Trajectory& trajectory) {
19 trajectory_planning_msgs::trajectory_access::initializeTrajectory(trajectory, trajectory_planning_msgs::msg::DRIVABLE::TYPE_ID,
20 n_shots_ + 1);
21}
22
23std::vector<double> TrajectoryOptimizationAckermannNode::getBiLevelX0(const perception_msgs::msg::EgoData& ego_data) {
24 // transform latest trajectory to current base_link frame
25 trajectory_planning_msgs::msg::Trajectory tf_trajectory;
26 try {
27 tf_trajectory = tf2_buffer_->transform(latest_valid_trajectory_, vehicle_frame_id_, tf2_ros::fromMsg(ego_data.header.stamp),
28 fixed_over_time_frame_id_, tf2::durationFromSec(0.01));
29 } catch (tf2::TransformException& ex) {
30 RCLCPP_WARN(this->get_logger(), "Transformation is not available. Init high-level instead. Ex: %s", ex.what());
31 return getHighLevelX0(ego_data);
32 }
33
34 // fill vectors with state values from the transformed trajectory
35 std::vector<double> TIME, V, Y, A, THETA, DELTA;
36 for (int i = 0; i < trajectory_planning_msgs::trajectory_access::getSamplePointSize(tf_trajectory); i++) {
37 TIME.push_back(trajectory_planning_msgs::trajectory_access::getT(tf_trajectory, i));
38 Y.push_back(trajectory_planning_msgs::trajectory_access::getY(tf_trajectory, i));
39 V.push_back(trajectory_planning_msgs::trajectory_access::getV(tf_trajectory, i));
40 A.push_back(trajectory_planning_msgs::trajectory_access::getA(tf_trajectory, i));
41 THETA.push_back(trajectory_planning_msgs::trajectory_access::getTheta(tf_trajectory, i));
42 DELTA.push_back(trajectory_planning_msgs::trajectory_access::getDeltaAck(tf_trajectory, i));
43 }
44
45 // interpolate target states by time from the extracted vectors; if not successful, set to ego state (high-level initialization)
46 double v_tgt = 0.0, a_tgt = 0.0, y_tgt = 0.0, theta_tgt = 0.0, delta_tgt = 0.0;
47 double des_time = (rclcpp::Time(ego_data.header.stamp) - rclcpp::Time(tf_trajectory.header.stamp)).seconds();
48 if (!linearInterpolation(TIME, Y, des_time, y_tgt)) y_tgt = 0.0;
49 if (!linearInterpolation(TIME, V, des_time, v_tgt)) v_tgt = perception_msgs::object_access::getVelLon(ego_data);
50 if (!linearInterpolation(TIME, A, des_time, a_tgt)) a_tgt = perception_msgs::object_access::getAccLon(ego_data);
51 if (!linearInterpolation(TIME, THETA, des_time, theta_tgt, true)) theta_tgt = 0.0;
52 if (!linearInterpolation(TIME, DELTA, des_time, delta_tgt)) {
53 delta_tgt = perception_msgs::object_access::getSteeringAngleAck(ego_data);
54 }
55
56 RCLCPP_DEBUG(this->get_logger(), "y_tgt: %f, v_tgt: %f, a_tgt: %f, theta_tgt: %f, delta_tgt: %f", y_tgt, v_tgt, a_tgt,
57 theta_tgt, delta_tgt);
58
59 // handle thresholds for bi-level stabilization (which means, using ego state as initial state for the optimization)
60 // longitudinal reinits
61 if (fabs(v_tgt - perception_msgs::object_access::getVelLon(ego_data)) > bi_level_dV_ ||
62 fabs(a_tgt - perception_msgs::object_access::getAccLon(ego_data)) > bi_level_dA_) {
63 RCLCPP_WARN(this->get_logger(), "Lon reinit: v_tgt: %f, a_tgt: %f, ego_v: %f, ego_a: %f", v_tgt, a_tgt,
64 perception_msgs::object_access::getVelLon(ego_data), perception_msgs::object_access::getAccLon(ego_data));
65 v_tgt = perception_msgs::object_access::getVelLon(ego_data);
66 a_tgt = perception_msgs::object_access::getAccLon(ego_data);
67 }
68 // lateral reinits
69 if (fabs(y_tgt) > bi_level_dY_ || fabs(theta_tgt) > bi_level_dYaw_ * M_PI / 180.0) {
70 RCLCPP_WARN(this->get_logger(), "Lat reinit: y_tgt: %f, theta_tgt: %f", y_tgt, theta_tgt);
71 y_tgt = 0.0;
72 theta_tgt = 0.0;
73 delta_tgt = perception_msgs::object_access::getSteeringAngleAck(ego_data);
74 } else if (fabs(delta_tgt - perception_msgs::object_access::getSteeringAngleAck(ego_data)) > bi_level_dDelta_ * M_PI / 180.0) {
75 RCLCPP_WARN(this->get_logger(), "Delta reinit: delta_tgt: %f, ego_delta: %f", delta_tgt,
76 perception_msgs::object_access::getSteeringAngleAck(ego_data));
77 delta_tgt = perception_msgs::object_access::getSteeringAngleAck(ego_data);
78 }
79
80 std::vector<double> x_init(*nlp_dims_->nx, 0.0);
81 x_init[0] = 0.0;
82 x_init[1] = y_tgt;
83 x_init[2] = 0.0;
84 x_init[3] = v_tgt;
85 x_init[4] = a_tgt;
86 x_init[5] = theta_tgt;
87 x_init[6] = delta_tgt;
88
89 return x_init;
90}
91
92std::vector<double> TrajectoryOptimizationAckermannNode::getHighLevelX0(const perception_msgs::msg::EgoData& ego_data) {
93 std::vector<double> x_init(*nlp_dims_->nx, 0.0);
94 x_init[3] = perception_msgs::object_access::getVelLon(ego_data);
95 x_init[4] = perception_msgs::object_access::getAccLon(ego_data);
96 x_init[6] = perception_msgs::object_access::getSteeringAngleAck(ego_data);
97
98 return x_init;
99}
100
101void TrajectoryOptimizationAckermannNode::convertToTrajectoryMsg(trajectory_planning_msgs::msg::Trajectory& trajectory) {
102 for (int i = 0; i <= n_shots_; ++i) {
103 trajectory_planning_msgs::trajectory_access::setX(trajectory, xtraj_[i * *nlp_dims_->nx + 0], i);
104 trajectory_planning_msgs::trajectory_access::setY(trajectory, xtraj_[i * *nlp_dims_->nx + 1], i);
105 trajectory_planning_msgs::trajectory_access::setS(trajectory, xtraj_[i * *nlp_dims_->nx + 2], i);
106 trajectory_planning_msgs::trajectory_access::setV(trajectory, xtraj_[i * *nlp_dims_->nx + 3], i);
107 trajectory_planning_msgs::trajectory_access::setA(trajectory, xtraj_[i * *nlp_dims_->nx + 4], i);
108 trajectory_planning_msgs::trajectory_access::setTheta(trajectory, xtraj_[i * *nlp_dims_->nx + 5], i);
109 trajectory_planning_msgs::trajectory_access::setDeltaAck(trajectory, xtraj_[i * *nlp_dims_->nx + 6], i);
110 }
111}
112
113} // namespace trajectory_optimization
void convertToTrajectoryMsg(trajectory_planning_msgs::msg::Trajectory &trajectory) override
Maps the optimized state trajectory into a trajectory message for a kinematic bicycle model with Acke...
std::vector< double > getBiLevelX0(const perception_msgs::msg::EgoData &ego_data) override
Computes the initial optimizer state using bi-level stabilizaion.
TrajectoryOptimizationAckermannNode(const rclcpp::NodeOptions &options)
Initializes the optimization node for a kinematic bicycle model with Ackermann steering.
void initializeTrajectory(trajectory_planning_msgs::msg::Trajectory &trajectory) override
Initializes a drivable trajectory message for a kinematic bicycle model with Ackermann steering.
std::vector< double > getHighLevelX0(const perception_msgs::msg::EgoData &ego_data) override
Computes the initial optimizer state using high-level stabilization.
trajectory_planning_msgs::msg::Trajectory latest_valid_trajectory_
bool linearInterpolation(const std::vector< double > &X, const std::vector< double > &Y, const double &desired_x, double &output_y, const bool wrap_angle=false)
Interpolates a value from sampled data and optionally handles angle wrap-around.
Definition utils.cpp:21
void declareAndLoadParameter(const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
Declares a ROS parameter, loads its value and optionally registers it for runtime updates.
Namespace for trajectory_optimization package.