trajectory_optimization v1.3.1
Loading...
Searching...
No Matches
trajectory_optimization_rws.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
4#include <limits>
5
7
8#include <rclcpp_components/register_node_macro.hpp>
9
10RCLCPP_COMPONENTS_REGISTER_NODE(trajectory_optimization::TrajectoryOptimizationRWSNode)
11
14 : TrajectoryOptimizationNode("TrajectoryOptimizationRWSNode", options) {
15 this->declareAndLoadParameter("distance_front_axle", distance_front_axle_, "Distance from center of gravity to front axle [m]");
16 this->declareAndLoadParameter("distance_rear_axle", distance_rear_axle_, "Distance from center of gravity to rear axle [m]");
17 this->declareAndLoadParameter("bi_level_dDelta_front", bi_level_dDelta_front_,
18 "Threshold for bi-level stabilization: maximum front steering angle difference [degree]");
19 this->declareAndLoadParameter("bi_level_dDelta_rear", bi_level_dDelta_rear_,
20 "Threshold for bi-level stabilization: maximum rear steering angle difference [degree]");
21}
22
23void TrajectoryOptimizationRWSNode::initializeTrajectory(trajectory_planning_msgs::msg::Trajectory& trajectory) {
24 trajectory_planning_msgs::trajectory_access::initializeTrajectory(
25 trajectory, trajectory_planning_msgs::msg::DRIVABLERWS::TYPE_ID, n_shots_ + 1);
26}
27
28std::vector<double> TrajectoryOptimizationRWSNode::getBiLevelX0(const perception_msgs::msg::EgoData& ego_data) {
29 // transform latest trajectory to current base_link frame
30 trajectory_planning_msgs::msg::Trajectory tf_trajectory;
31 try {
32 tf_trajectory = tf2_buffer_->transform(latest_valid_trajectory_, vehicle_frame_id_, tf2_ros::fromMsg(ego_data.header.stamp),
33 fixed_over_time_frame_id_, tf2::durationFromSec(0.01));
34 } catch (tf2::TransformException& ex) {
35 RCLCPP_WARN(this->get_logger(), "Transformation is not available. Init high-level instead. Ex: %s", ex.what());
36 return getHighLevelX0(ego_data);
37 }
38
39 // fill vectors with state values from the transformed trajectory
40 std::vector<double> TIME, V, Y, A, THETA, DELTA_FRONT, DELTA_REAR;
41 for (int i = 0; i < trajectory_planning_msgs::trajectory_access::getSamplePointSize(tf_trajectory); i++) {
42 TIME.push_back(trajectory_planning_msgs::trajectory_access::getT(tf_trajectory, i));
43 Y.push_back(trajectory_planning_msgs::trajectory_access::getY(tf_trajectory, i));
44 V.push_back(trajectory_planning_msgs::trajectory_access::getV(tf_trajectory, i));
45 A.push_back(trajectory_planning_msgs::trajectory_access::getA(tf_trajectory, i));
46 THETA.push_back(trajectory_planning_msgs::trajectory_access::getTheta(tf_trajectory, i));
47 DELTA_FRONT.push_back(trajectory_planning_msgs::trajectory_access::getDeltaFront(tf_trajectory, i));
48 DELTA_REAR.push_back(trajectory_planning_msgs::trajectory_access::getDeltaRear(tf_trajectory, i));
49 }
50
51 // interpolate target states by time from the extracted vectors; if not successful, set to ego state (high-level initialization)
52 double v_tgt = 0.0, a_tgt = 0.0, y_tgt = 0.0, theta_tgt = 0.0, delta_front_tgt = 0.0, delta_rear_tgt = 0.0;
53 double des_time = (rclcpp::Time(ego_data.header.stamp) - rclcpp::Time(tf_trajectory.header.stamp)).seconds();
54 if (!linearInterpolation(TIME, Y, des_time, y_tgt)) y_tgt = 0.0;
55 if (!linearInterpolation(TIME, THETA, des_time, theta_tgt, true)) theta_tgt = 0.0;
56 if (!linearInterpolation(TIME, V, des_time, v_tgt)) v_tgt = perception_msgs::object_access::getVelocityMagnitude(ego_data);
57 if (!linearInterpolation(TIME, A, des_time, a_tgt)) {
58 a_tgt = projectVectorAonV(perception_msgs::object_access::getAcceleration(ego_data),
59 perception_msgs::object_access::getVelocity(ego_data));
60 }
61 if (!linearInterpolation(TIME, DELTA_FRONT, des_time, delta_front_tgt)) {
62 delta_front_tgt = perception_msgs::object_access::getSteeringAngleFront(ego_data);
63 }
64 if (!linearInterpolation(TIME, DELTA_REAR, des_time, delta_rear_tgt)) {
65 delta_rear_tgt = perception_msgs::object_access::getSteeringAngleRear(ego_data);
66 }
67
68 RCLCPP_DEBUG(this->get_logger(), "y_tgt: %f, v_tgt: %f, a_tgt: %f, theta_tgt: %f, delta_front_tgt: %f, delta_rear_tgt: %f",
69 y_tgt, v_tgt, a_tgt, theta_tgt, delta_front_tgt, delta_rear_tgt);
70
71 // handle thresholds for bi-level stabilization (which means, using ego state as initial state for the optimization)
72 // longitudinal reinits
73 double a_path = projectVectorAonV(perception_msgs::object_access::getAcceleration(ego_data),
74 perception_msgs::object_access::getVelocity(ego_data));
75 if (fabs(v_tgt - perception_msgs::object_access::getVelocityMagnitude(ego_data)) > bi_level_dV_ ||
76 fabs(a_tgt - a_path) > bi_level_dA_) {
77 v_tgt = perception_msgs::object_access::getVelocityMagnitude(ego_data);
78 a_tgt = a_path;
79 }
80 // lateral reinits
81 if (fabs(y_tgt) > bi_level_dY_ || fabs(theta_tgt) > bi_level_dYaw_ * M_PI / 180.0) {
82 y_tgt = 0.0;
83 theta_tgt = 0.0;
84 delta_front_tgt = perception_msgs::object_access::getSteeringAngleFront(ego_data);
85 delta_rear_tgt = perception_msgs::object_access::getSteeringAngleRear(ego_data);
86 } else if (fabs(delta_front_tgt - perception_msgs::object_access::getSteeringAngleFront(ego_data)) >
87 bi_level_dDelta_front_ * M_PI / 180.0) {
88 delta_front_tgt = perception_msgs::object_access::getSteeringAngleFront(ego_data);
89 } else if (fabs(delta_rear_tgt - perception_msgs::object_access::getSteeringAngleRear(ego_data)) >
90 bi_level_dDelta_rear_ * M_PI / 180.0) {
91 delta_rear_tgt = perception_msgs::object_access::getSteeringAngleRear(ego_data);
92 }
93
94 std::vector<double> x_init(*nlp_dims_->nx, 0.0);
95 x_init[0] = 0.0;
96 x_init[1] = y_tgt;
97 x_init[2] = 0.0;
98 x_init[3] = v_tgt;
99 x_init[4] = a_tgt;
100 x_init[5] = theta_tgt;
101 x_init[6] = delta_front_tgt;
102 x_init[7] = delta_rear_tgt;
103
104 return x_init;
105}
106
107std::vector<double> TrajectoryOptimizationRWSNode::getHighLevelX0(const perception_msgs::msg::EgoData& ego_data) {
108 std::vector<double> x_init(*nlp_dims_->nx, 0.0);
109
110 x_init[3] = perception_msgs::object_access::getVelocityMagnitude(ego_data);
111 x_init[4] = projectVectorAonV(perception_msgs::object_access::getAcceleration(ego_data),
112 perception_msgs::object_access::getVelocity(ego_data));
113 x_init[6] = perception_msgs::object_access::getSteeringAngleFront(ego_data);
114 x_init[7] = perception_msgs::object_access::getSteeringAngleRear(ego_data);
115
116 return x_init;
117}
118
119void TrajectoryOptimizationRWSNode::convertToTrajectoryMsg(trajectory_planning_msgs::msg::Trajectory& trajectory) {
120 for (int i = 0; i <= n_shots_; ++i) {
121 trajectory_planning_msgs::trajectory_access::setX(trajectory, xtraj_[i * *nlp_dims_->nx + 0], i);
122 trajectory_planning_msgs::trajectory_access::setY(trajectory, xtraj_[i * *nlp_dims_->nx + 1], i);
123 trajectory_planning_msgs::trajectory_access::setS(trajectory, xtraj_[i * *nlp_dims_->nx + 2], i);
124 trajectory_planning_msgs::trajectory_access::setV(trajectory, xtraj_[i * *nlp_dims_->nx + 3], i);
125 trajectory_planning_msgs::trajectory_access::setA(trajectory, xtraj_[i * *nlp_dims_->nx + 4], i);
126 trajectory_planning_msgs::trajectory_access::setTheta(trajectory, xtraj_[i * *nlp_dims_->nx + 5], i);
127 trajectory_planning_msgs::trajectory_access::setDeltaFront(trajectory, xtraj_[i * *nlp_dims_->nx + 6], i);
128 trajectory_planning_msgs::trajectory_access::setDeltaRear(trajectory, xtraj_[i * *nlp_dims_->nx + 7], i);
129 trajectory_planning_msgs::trajectory_access::setBeta(
130 trajectory, xtraj_[i * *nlp_dims_->nx + 6], xtraj_[i * *nlp_dims_->nx + 7], distance_front_axle_, distance_rear_axle_, i);
131 }
132}
133
134double TrajectoryOptimizationRWSNode::computeVehicleSlipAngle(const double& delta_front, const double& delta_rear) const {
135 double wheel_base = distance_front_axle_ + distance_rear_axle_;
136 double slip_angle =
137 atan(distance_rear_axle_ / wheel_base * tan(delta_front) + distance_front_axle_ / wheel_base * tan(delta_rear));
138 return slip_angle;
139}
140
141double TrajectoryOptimizationRWSNode::projectVectorAonV(const geometry_msgs::msg::Vector3& a,
142 const geometry_msgs::msg::Vector3& v) {
143 double v_magnitude_squared = v.x * v.x + v.y * v.y;
144 if (v_magnitude_squared < std::numeric_limits<double>::epsilon()) {
145 return 0.0;
146 }
147 double scale = (a.x * v.x + a.y * v.y) / v_magnitude_squared;
148 return scale * std::sqrt(v_magnitude_squared);
149}
150
151} // namespace trajectory_optimization
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.
void convertToTrajectoryMsg(trajectory_planning_msgs::msg::Trajectory &trajectory) override
Maps the optimized state trajectory into a trajectory message for a kinematic bicycle model with rear...
std::vector< double > getHighLevelX0(const perception_msgs::msg::EgoData &ego_data) override
Computes the initial optimizer state using high-level stabilization.
std::vector< double > getBiLevelX0(const perception_msgs::msg::EgoData &ego_data) override
Computes the initial optimizer state using bi-level stabilizaion.
static double projectVectorAonV(const geometry_msgs::msg::Vector3 &a, const geometry_msgs::msg::Vector3 &v)
Projects the acceleration vector onto the current direction of motion.
double computeVehicleSlipAngle(const double &delta_front, const double &delta_rear) const
Computes the kinematic vehicle slip angle from front and rear steering angles.
TrajectoryOptimizationRWSNode(const rclcpp::NodeOptions &options)
Initializes the optimization node for a kinematic bicycle model with rear wheel steering.
void initializeTrajectory(trajectory_planning_msgs::msg::Trajectory &trajectory) override
Initializes a drivable trajectory message for a kinematic bicycle model with rear wheel steering.
Namespace for trajectory_optimization package.