Skip to content

Commit 91936bd

Browse files
Add multiple examples of IPDDP trajectory (#84)
* Add ipddp car test * Add ipddp pendulum test * Add car example using IPDDP * Add regularization and parallel forward pass * Add feasible infeasible unicycle path
1 parent 6fca7e3 commit 91936bd

8 files changed

+658
-297
lines changed

examples/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ target_link_libraries(cddp_bicycle cddp)
1919
add_executable(cddp_car cddp_car.cpp)
2020
target_link_libraries(cddp_car cddp)
2121

22+
add_executable(cddp_car_ipddp cddp_car_ipddp.cpp)
23+
target_link_libraries(cddp_car_ipddp cddp)
24+
2225
add_executable(cddp_cartpole cddp_cartpole.cpp)
2326
target_link_libraries(cddp_cartpole cddp)
2427

@@ -31,6 +34,9 @@ target_link_libraries(cddp_unicycle cddp)
3134
add_executable(cddp_unicycle_safe cddp_unicycle_safe.cpp)
3235
target_link_libraries(cddp_unicycle_safe cddp)
3336

37+
add_executable(cddp_unicycle_safe_ipddp cddp_unicycle_safe_ipddp.cpp)
38+
target_link_libraries(cddp_unicycle_safe_ipddp cddp)
39+
3440
add_executable(cddp_manipulator cddp_manipulator.cpp)
3541
target_link_libraries(cddp_manipulator cddp)
3642

examples/cddp_car_ipddp.cpp

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
Copyright 2024 Tomo Sasaki
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#include <iostream>
18+
#include <vector>
19+
#include <cmath>
20+
#include <map>
21+
#include <string>
22+
#include "cddp.hpp"
23+
24+
namespace plt = matplotlibcpp;
25+
26+
// Define the CarParkingObjective
27+
namespace cddp {
28+
29+
class CarParkingObjective : public NonlinearObjective {
30+
public:
31+
CarParkingObjective(const Eigen::VectorXd& goal_state, double timestep)
32+
: NonlinearObjective(timestep), reference_state_(goal_state) {
33+
cu_ = Eigen::Vector2d(1e-2, 1e-4);
34+
cf_ = Eigen::Vector4d(0.1, 0.1, 1.0, 0.3);
35+
pf_ = Eigen::Vector4d(0.01, 0.01, 0.01, 1.0);
36+
cx_ = Eigen::Vector2d(1e-3, 1e-3);
37+
px_ = Eigen::Vector2d(0.1, 0.1);
38+
}
39+
40+
double running_cost(const Eigen::VectorXd& state,
41+
const Eigen::VectorXd& control,
42+
int index) const override {
43+
double lu = cu_.dot(control.array().square().matrix());
44+
Eigen::VectorXd xy_state = state.head(2);
45+
double lx = cx_.dot(sabs(xy_state, px_));
46+
return lu + lx;
47+
}
48+
49+
double terminal_cost(const Eigen::VectorXd& final_state) const override {
50+
return cf_.dot(sabs(final_state, pf_)) + running_cost(final_state, Eigen::VectorXd::Zero(2), 0);
51+
}
52+
53+
private:
54+
Eigen::VectorXd sabs(const Eigen::VectorXd& x, const Eigen::VectorXd& p) const {
55+
return ((x.array().square() / p.array().square() + 1.0).sqrt() * p.array() - p.array()).matrix();
56+
}
57+
58+
Eigen::VectorXd reference_state_;
59+
Eigen::Vector2d cu_;
60+
Eigen::Vector4d cf_;
61+
Eigen::Vector4d pf_;
62+
Eigen::Vector2d cx_;
63+
Eigen::Vector2d px_;
64+
};
65+
66+
} // namespace cddp
67+
68+
namespace {
69+
void plotCarBox(const Eigen::VectorXd& state, const Eigen::VectorXd& control,
70+
double length, double width, const std::string& color) {
71+
double x = state(0);
72+
double y = state(1);
73+
double theta = state(2);
74+
double steering = control(1);
75+
76+
// Compute car corner points (5 points to close the polygon)
77+
std::vector<double> car_x(5), car_y(5);
78+
car_x[0] = x + length/2 * cos(theta) - width/2 * sin(theta);
79+
car_y[0] = y + length/2 * sin(theta) + width/2 * cos(theta);
80+
car_x[1] = x + length/2 * cos(theta) + width/2 * sin(theta);
81+
car_y[1] = y + length/2 * sin(theta) - width/2 * cos(theta);
82+
car_x[2] = x - length/2 * cos(theta) + width/2 * sin(theta);
83+
car_y[2] = y - length/2 * sin(theta) - width/2 * cos(theta);
84+
car_x[3] = x - length/2 * cos(theta) - width/2 * sin(theta);
85+
car_y[3] = y - length/2 * sin(theta) + width/2 * cos(theta);
86+
car_x[4] = car_x[0];
87+
car_y[4] = car_y[0];
88+
89+
// Plot the car body
90+
std::map<std::string, std::string> keywords;
91+
keywords["color"] = color;
92+
plt::plot(car_x, car_y, keywords);
93+
94+
// Plot the base point (center of rear axle) in red with a marker
95+
std::vector<double> base_x = {x};
96+
std::vector<double> base_y = {y};
97+
keywords["color"] = "red";
98+
keywords["marker"] = "o";
99+
plt::plot(base_x, base_y, keywords);
100+
101+
// Plot the steering direction in green
102+
double front_x = x + length/2 * cos(theta);
103+
double front_y = y + length/2 * sin(theta);
104+
double steering_length = width/2;
105+
double steering_angle = theta + steering;
106+
double steering_end_x = front_x + steering_length * cos(steering_angle);
107+
double steering_end_y = front_y + steering_length * sin(steering_angle);
108+
std::vector<double> steer_x = {front_x, steering_end_x};
109+
std::vector<double> steer_y = {front_y, steering_end_y};
110+
keywords["color"] = "green";
111+
keywords.erase("marker");
112+
plt::plot(steer_x, steer_y, keywords);
113+
}
114+
}
115+
116+
// Test case that solves the car parking problem, creates an animation, and saves the GIF.
117+
int main() {
118+
// Problem parameters
119+
const int state_dim = 4; // [x, y, theta, v]
120+
const int control_dim = 2; // [wheel_angle, acceleration]
121+
const int horizon = 500;
122+
const double timestep = 0.03;
123+
const std::string integration_type = "euler";
124+
125+
// Create a Car instance with given parameters
126+
double wheelbase = 2.0;
127+
std::unique_ptr<cddp::DynamicalSystem> system =
128+
std::make_unique<cddp::Car>(timestep, wheelbase, integration_type);
129+
130+
// Define initial and goal states
131+
Eigen::VectorXd initial_state(state_dim);
132+
initial_state << 1.0, 1.0, 1.5 * M_PI, 0.0;
133+
Eigen::VectorXd goal_state(state_dim);
134+
goal_state << 0.0, 0.0, 0.0, 0.0; // Desired parking state
135+
136+
// Create the nonlinear objective for car parking
137+
auto objective = std::make_unique<cddp::CarParkingObjective>(goal_state, timestep);
138+
139+
// Create CDDP solver for the car model
140+
cddp::CDDP cddp_solver(initial_state, goal_state, horizon, timestep);
141+
cddp_solver.setDynamicalSystem(std::move(system));
142+
cddp_solver.setObjective(std::move(objective));
143+
144+
// Define control constraints
145+
Eigen::VectorXd control_lower_bound(control_dim);
146+
control_lower_bound << -0.5, -2.0; // [steering_angle, acceleration]
147+
Eigen::VectorXd control_upper_bound(control_dim);
148+
control_upper_bound << 0.5, 2.0;
149+
cddp_solver.addConstraint("ControlConstraint", std::make_unique<cddp::ControlConstraint>(control_upper_bound));
150+
151+
// Set solver options
152+
cddp::CDDPOptions options;
153+
options.max_iterations = 600;
154+
options.verbose = false; // Disable verbose output for the test
155+
options.cost_tolerance = 1e-7;
156+
options.grad_tolerance = 1e-4;
157+
options.regularization_type = "none";
158+
options.debug = false;
159+
options.use_parallel = false;
160+
options.num_threads = 1;
161+
options.barrier_coeff = 1e-1;
162+
cddp_solver.setOptions(options);
163+
164+
// Initialize the trajectory with zero controls
165+
std::vector<Eigen::VectorXd> X(horizon + 1, Eigen::VectorXd::Zero(state_dim));
166+
std::vector<Eigen::VectorXd> U(horizon, Eigen::VectorXd::Zero(control_dim));
167+
X[0] = initial_state;
168+
for (int i = 0; i < horizon; ++i) {
169+
U[i](0) = 0.0;
170+
U[i](1) = 0.0;
171+
X[i + 1] = cddp_solver.getSystem().getDiscreteDynamics(X[i], U[i]);
172+
}
173+
cddp_solver.setInitialTrajectory(X, U);
174+
175+
// Solve the problem using IPDDP
176+
cddp::CDDPSolution solution = cddp_solver.solve("IPDDP");
177+
178+
179+
// Prepare trajectory data for plotting
180+
std::vector<double> x_hist, y_hist;
181+
for (const auto& state : solution.state_sequence) {
182+
x_hist.push_back(state(0));
183+
y_hist.push_back(state(1));
184+
}
185+
186+
// Plot the trajectory
187+
plt::plot(x_hist, y_hist, "b-");
188+
plt::show();
189+
}

0 commit comments

Comments
 (0)