Skip to content

Commit ec7d663

Browse files
Debug and additional fix for ilqr optimization
1 parent d916d1e commit ec7d663

File tree

6 files changed

+88
-49
lines changed

6 files changed

+88
-49
lines changed

ilqr_trajectory_tracker/demos/ilqr_optimizer_demo.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ int main(int argc, char ** argv)
4949

5050
Matrix3d Q = Matrix3d::Identity() * 10;
5151
Matrix2d R = Matrix2d::Identity() * 0.1;
52-
double alpha = 1;
5352

5453
ilqr_trajectory_tracker::NewtonOptimizer<DiffDriveRobotModel> newton_optimizer;
5554
newton_optimizer.setIterationNumber(10);
56-
newton_optimizer.setAlpha(alpha);
5755

5856
const auto start{std::chrono::steady_clock::now()};
59-
auto u_optimal = newton_optimizer.optimize(x_feasible, Q, R, dt);
57+
// TODO: pass parameter of actual robot pose instead of
58+
// passing the first state of feasible trajectory
59+
auto u_optimal = newton_optimizer.optimize(x_feasible[0], x_feasible, Q, R, dt);
6060
const auto end{std::chrono::steady_clock::now()};
6161

6262
const std::chrono::duration<double> elapsed_seconds{end - start};

ilqr_trajectory_tracker/include/ilqr_trajectory_tracker/ilqr_optimizer.hpp

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ class NewtonOptimizer : public Optimizer
5757

5858
std::tuple<std::vector<typename RobotModel::StateT>,
5959
std::vector<typename RobotModel::InputT>> forwardPass(
60+
const typename RobotModel::StateT x0,
6061
const std::vector<typename RobotModel::StateT> & x_feasible,
6162
const std::vector<typename RobotModel::InputT> & u_feasible,
6263
const std::vector<MatrixXd> & K_gains, const double dt, const double alpha);
6364

6465
std::vector<typename RobotModel::InputT> optimize(
66+
const typename RobotModel::StateT x0,
6567
const std::vector<typename RobotModel::StateT> & x_feasible, const Matrix3d & Q,
6668
const Matrix2d & R, const double dt);
6769

@@ -71,15 +73,12 @@ class NewtonOptimizer : public Optimizer
7173

7274
void setIterationNumber(const size_t iteration_number);
7375

74-
void setAlpha(const double alpha);
75-
7676
void setInputConstraints(
7777
typename RobotModel::InputT input_limits_min,
7878
typename RobotModel::InputT input_limits_max);
7979

8080
private:
8181
std::unique_ptr<RobotModel> robot_model_;
82-
double alpha_;
8382
size_t iteration_number_;
8483
};
8584

@@ -136,6 +135,7 @@ std::vector<MatrixXd> NewtonOptimizer<RobotModel>::backwardPass(
136135
template<typename RobotModel>
137136
std::tuple<std::vector<typename RobotModel::StateT>,
138137
std::vector<typename RobotModel::InputT>> NewtonOptimizer<RobotModel>::forwardPass(
138+
const typename RobotModel::StateT x0,
139139
const std::vector<typename RobotModel::StateT> & x_feasible,
140140
const std::vector<typename RobotModel::InputT> & u_feasible,
141141
const std::vector<MatrixXd> & K_gains, const double dt, const double alpha)
@@ -147,10 +147,8 @@ std::tuple<std::vector<typename RobotModel::StateT>,
147147
std::vector<typename RobotModel::InputT> u_applied(input_size);
148148

149149
// assert trajectory_size > 0
150-
x_tracked[0] = x_feasible[0];
151-
for (typename std::vector<typename RobotModel::StateT>::difference_type i = 0,
152-
max_difference = std::distance(x_feasible.begin(), std::prev(x_feasible.end(), 1));
153-
i < max_difference; ++i)
150+
x_tracked[0] = x0;
151+
for (size_t i = 0; i < x_feasible.size() - 1; ++i)
154152
{
155153
auto x_error = x_tracked[i] - x_feasible[i];
156154
Vector<double, 4> z_error;
@@ -180,12 +178,13 @@ std::tuple<MatrixXd, MatrixXd> NewtonOptimizer<RobotModel>::solveDiscreteLQRProb
180178

181179
template<typename RobotModel>
182180
std::vector<typename RobotModel::InputT> NewtonOptimizer<RobotModel>::optimize(
181+
const typename RobotModel::StateT x0,
183182
const std::vector<typename RobotModel::StateT> & x_trajectory, const Matrix3d & Q,
184183
const Matrix2d & R, const double dt)
185184
{
186185
// assert trajectory_size > 0
187186

188-
double alpha = alpha_;
187+
double alpha = 1.0;
189188

190189
std::vector<typename RobotModel::StateT> x_best_trajectory;
191190
std::vector<typename RobotModel::InputT> u_best_trajectory;
@@ -198,7 +197,7 @@ std::vector<typename RobotModel::InputT> NewtonOptimizer<RobotModel>::optimize(
198197
double previous_best_trajectory_cost = best_trajectory_cost;
199198
for (size_t i = 0; i < iteration_number_; ++i) {
200199
auto K_gain_list = this->backwardPass(x_trajectory, u_optimized, Q, R, dt);
201-
auto [x_tracked, u_tracked] = this->forwardPass(
200+
auto [x_tracked, u_tracked] = this->forwardPass(x0,
202201
x_trajectory, u_optimized, K_gain_list, dt,
203202
alpha);
204203
u_optimized = u_tracked;
@@ -244,12 +243,6 @@ void NewtonOptimizer<RobotModel>::setIterationNumber(const size_t iteration_numb
244243
iteration_number_ = iteration_number;
245244
}
246245

247-
template<typename RobotModel>
248-
void NewtonOptimizer<RobotModel>::setAlpha(const double alpha)
249-
{
250-
alpha_ = alpha;
251-
}
252-
253246
template<typename RobotModel>
254247
void NewtonOptimizer<RobotModel>::setInputConstraints(
255248
typename RobotModel::InputT input_limits_min,

nav2_frenet_ilqr_controller/include/nav2_frenet_ilqr_controller/frenet_ilqr_controller.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class FrenetILQRController : public nav2_core::Controller
110110
nav2_core::GoalChecker * /*goal_checker*/) override;
111111

112112
Vector2d findOptimalInputForTrajectory(
113-
const geometry_msgs::msg::PoseStamped & robot_pose,
113+
const Vector3d & x0,
114114
const frenet_trajectory_planner::CartesianTrajectory & robot_cartesian_trajectory);
115115

116116
bool cancel() override;

nav2_frenet_ilqr_controller/include/nav2_frenet_ilqr_controller/parameter_handler.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ struct Parameters
3737
double transform_tolerance;
3838
double time_discretization;
3939
int iteration_number;
40-
double alpha;
40+
std::string robot_type;
41+
double wheelbase;
4142
frenet_trajectory_planner::FrenetTrajectoryPlannerConfig frenet_trajectory_planner_config;
4243
};
4344

nav2_frenet_ilqr_controller/src/frenet_ilqr_controller.cpp

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ nav_msgs::msg::Path FrenetILQRController::truncateGlobalPlanWithLookAheadDist(
206206
}
207207

208208
Vector2d FrenetILQRController::findOptimalInputForTrajectory(
209-
const geometry_msgs::msg::PoseStamped & /*robot_pose*/,
209+
const Vector3d & x0,
210210
const frenet_trajectory_planner::CartesianTrajectory & robot_cartesian_trajectory)
211211
{
212212

@@ -219,7 +219,8 @@ Vector2d FrenetILQRController::findOptimalInputForTrajectory(
219219
using ilqr_trajectory_tracker::AckermannRobotModelInput;
220220

221221
std::vector<AckermannRobotModelState> X_feasible;
222-
for (auto cartesian_state : robot_cartesian_trajectory) {
222+
for (size_t i = 1; i < robot_cartesian_trajectory.size(); ++i) {
223+
auto cartesian_state = robot_cartesian_trajectory[i];
223224
AckermannRobotModelState x;
224225
x << cartesian_state[0],
225226
cartesian_state[3],
@@ -229,26 +230,62 @@ Vector2d FrenetILQRController::findOptimalInputForTrajectory(
229230

230231
Matrix3d Q = Matrix3d::Identity() * 1;
231232
Matrix2d R = Matrix2d::Identity() * 0.2;
232-
double alpha = 1;
233-
double dt = 0.05;
234-
ilqr_trajectory_tracker::NewtonOptimizer<AckermannRobotModel> newton_optimizer(0.5);
235233

236-
AckermannRobotModelInput input_limits_min;
237-
input_limits_min << -0.5, -2.5;
234+
if (params_->robot_type == "ackermann") {
235+
using ilqr_trajectory_tracker::AckermannRobotModel;
236+
ilqr_trajectory_tracker::NewtonOptimizer<AckermannRobotModel> newton_optimizer(params_->wheelbase);
238237

239-
AckermannRobotModelInput input_limits_max;
240-
input_limits_max << 0.5, 2.5;
241-
newton_optimizer.setInputConstraints(input_limits_min, input_limits_max);
238+
Vector2d input_limits_min;
239+
input_limits_min << -0.5, -0.523599;
242240

243-
newton_optimizer.setIterationNumber(20);
244-
newton_optimizer.setAlpha(alpha);
245-
auto U_optimal = newton_optimizer.optimize(X_feasible, Q, R, dt);
241+
Vector2d input_limits_max;
242+
input_limits_max << 0.5, 0.523599;
243+
newton_optimizer.setInputConstraints(input_limits_min, input_limits_max);
246244

247-
if (U_optimal.empty()) {
248-
throw nav2_core::NoValidControl("Iterative LQR couldn't find any solution!");
249-
}
245+
newton_optimizer.setIterationNumber(20);
246+
auto U_optimal = newton_optimizer.optimize(x0, X_feasible, Q, R, params_->time_discretization);
247+
248+
RCLCPP_INFO(logger_, "--------------------");
249+
for (auto cstate : X_feasible) {
250+
RCLCPP_INFO(logger_, "[%f, %f, %f]", cstate[0], cstate[1], cstate[2]);
251+
}
252+
RCLCPP_INFO(logger_, "********************");
253+
254+
if (U_optimal.empty()) {
255+
throw nav2_core::NoValidControl("Iterative LQR couldn't find any solution!");
256+
}
257+
258+
Vector2d u_ackermann;
259+
u_ackermann << U_optimal[0][0], (U_optimal[0][0] / params_->wheelbase) * std::tan(U_optimal[0][1]);
260+
RCLCPP_INFO(logger_, "--------------------");
261+
for (auto u : U_optimal) {
262+
RCLCPP_INFO(logger_, "[%f, %f]", u[0], u[1]);
263+
}
264+
RCLCPP_INFO(logger_, "********************");
265+
266+
return u_ackermann;
267+
} else if (params_->robot_type == "diffdrive") {
268+
using ilqr_trajectory_tracker::DiffDriveRobotModel;
269+
ilqr_trajectory_tracker::NewtonOptimizer<DiffDriveRobotModel> newton_optimizer;
250270

251-
return U_optimal[0];
271+
Vector2d input_limits_min;
272+
input_limits_min << -0.5, -2.5;
273+
274+
Vector2d input_limits_max;
275+
input_limits_max << 0.5, 2.5;
276+
newton_optimizer.setInputConstraints(input_limits_min, input_limits_max);
277+
278+
newton_optimizer.setIterationNumber(20);
279+
auto U_optimal = newton_optimizer.optimize(x0, X_feasible, Q, R, params_->time_discretization);
280+
281+
if (U_optimal.empty()) {
282+
throw nav2_core::NoValidControl("Iterative LQR couldn't find any solution!");
283+
}
284+
285+
return U_optimal[0];
286+
} else {
287+
throw nav2_core::NoValidControl("Unknown robot type! Possible robot types : ackermann, diffdrive");
288+
}
252289
}
253290

254291
geometry_msgs::msg::TwistStamped FrenetILQRController::computeVelocityCommands(
@@ -289,19 +326,19 @@ geometry_msgs::msg::TwistStamped FrenetILQRController::computeVelocityCommands(
289326
frenet_trajectory_planner::CartesianState robot_cartesian_state =
290327
frenet_trajectory_planner::CartesianState::Zero();
291328
double robot_yaw = tf2::getYaw(robot_pose.pose.orientation);
292-
double linear_speed = speed.linear.x;
329+
double linear_speed = std::abs(speed.linear.x);
293330

294331
// if (std::abs(linear_speed) <= 0.5) {
295332
// params_->frenet_trajectory_planner_config.time_interval = 10;
296333
// }
297-
double max_curvature = 2.5;
298-
linear_speed = 1 / max_curvature;
334+
// double max_curvature = 2.5;
335+
// linear_speed = 1 / max_curvature;
299336
robot_cartesian_state[0] = robot_pose.pose.position.x;
300337
robot_cartesian_state[1] = linear_speed * std::cos(robot_yaw);
301-
robot_cartesian_state[2] = -linear_speed * std::sin(robot_yaw);
338+
// robot_cartesian_state[2] = -linear_speed * std::sin(robot_yaw);
302339
robot_cartesian_state[3] = robot_pose.pose.position.y;
303340
robot_cartesian_state[4] = linear_speed * std::sin(robot_yaw);
304-
robot_cartesian_state[5] = linear_speed * std::cos(robot_yaw);
341+
// robot_cartesian_state[5] = linear_speed * std::cos(robot_yaw);
305342
robot_cartesian_state[6] = robot_yaw;
306343

307344
frenet_trajectory_planner_.setFrenetTrajectoryPlannerConfig(
@@ -319,13 +356,16 @@ geometry_msgs::msg::TwistStamped FrenetILQRController::computeVelocityCommands(
319356
transformed_plan.header.frame_id,
320357
planned_cartesian_trajectory);
321358
frenet_plan = path_handler_->transformPath(costmap_ros_->getBaseFrameID(), frenet_plan);
322-
323359
planned_cartesian_trajectory = convertToCartesianTrajectory(frenet_plan);
324360

325361
truncated_path_pub_->publish(frenet_plan);
326362
robot_pose_pub_->publish(robot_pose);
327363

328-
auto u_opt = findOptimalInputForTrajectory(robot_pose, planned_cartesian_trajectory);
364+
path_handler_->transformPose(costmap_ros_->getBaseFrameID(), robot_pose, robot_pose);
365+
Vector3d c_state_robot;
366+
c_state_robot << robot_pose.pose.position.x, robot_pose.pose.position.y,
367+
tf2::getYaw(robot_pose.pose.orientation);
368+
auto u_opt = findOptimalInputForTrajectory(c_state_robot, planned_cartesian_trajectory);
329369

330370
// populate and return message
331371
geometry_msgs::msg::TwistStamped cmd_vel;

nav2_frenet_ilqr_controller/src/parameter_handler.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ ParameterHandler::ParameterHandler(
7878
node, plugin_name_ + ".ilqr_trajectory_tracker.iteration_number", rclcpp::ParameterValue(20));
7979

8080
declare_parameter_if_not_declared(
81-
node, plugin_name_ + ".ilqr_trajectory_tracker.alpha", rclcpp::ParameterValue(1.0));
82-
81+
node, plugin_name_ + ".robot_type", rclcpp::ParameterValue("diff_drive"));
82+
declare_parameter_if_not_declared(
83+
node, plugin_name_ + ".wheelbase", rclcpp::ParameterValue(2.5));
8384

8485
node->get_parameter(
8586
plugin_name_ + ".interpolate_curvature_after_goal",
@@ -122,7 +123,9 @@ ParameterHandler::ParameterHandler(
122123
node->get_parameter(
123124
plugin_name_ + ".ilqr_trajectory_tracker.iteration_number",
124125
params_.iteration_number);
125-
node->get_parameter(plugin_name_ + ".ilqr_trajectory_tracker.alpha", params_.alpha);
126+
127+
node->get_parameter(plugin_name_ + ".robot_type", params_.robot_type);
128+
node->get_parameter(plugin_name_ + ".wheelbase", params_.wheelbase);
126129

127130

128131
dynamic_params_handler_ = node->add_on_set_parameters_callback(
@@ -184,8 +187,10 @@ ParameterHandler::dynamicParametersCallback(
184187
} else {
185188
params_.iteration_number = parameter.as_int();
186189
}
187-
} else if (name == plugin_name_ + ".ilqr_trajectory_tracker.alpha") {
188-
params_.alpha = parameter.as_double();
190+
} else if (name == plugin_name_ + ".robot_type") {
191+
params_.robot_type = parameter.as_string();
192+
} else if (name == plugin_name_ + ".wheelbase") {
193+
params_.wheelbase = parameter.as_double();
189194
}
190195
}
191196

0 commit comments

Comments
 (0)