13
13
See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
*/
16
+
16
17
#include < iostream>
17
18
#include < vector>
18
19
#include < filesystem>
19
20
20
- #include " cddp.hpp"
21
+ #include " cddp.hpp" // Adjust include as needed for your CDDP framework and DubinsCar definition
21
22
22
23
namespace plt = matplotlibcpp;
23
24
namespace fs = std::filesystem;
24
25
25
26
int main () {
26
27
// Problem parameters
27
- int state_dim = 3 ;
28
- int control_dim = 2 ;
29
- int horizon = 100 ;
30
- double timestep = 0.03 ;
31
- std::string integration_type = " euler" ;
28
+ const int state_dim = 3 ; // [x, y, theta]
29
+ const int control_dim = 1 ; // [omega]
30
+ const int horizon = 100 ; // planning horizon
31
+ const double timestep = 0.03 ; // integration step
32
+ const std::string integration_type = " euler" ;
32
33
33
- // Create a dubins car instance
34
- std::unique_ptr<cddp::DynamicalSystem> system = std::make_unique<cddp::DubinsCar>(timestep, integration_type); // Create unique_ptr
34
+ // Create a DubinsCar instance (constant speed + single steering input)
35
+ double forward_speed = 1.0 ; // For example, 1.0 m/s
36
+ std::unique_ptr<cddp::DynamicalSystem> system =
37
+ std::make_unique<cddp::DubinsCar>(forward_speed, timestep, integration_type);
35
38
36
39
// Create objective function
40
+ // State cost matrix Q (typically zero or small if you only penalize final state heavily)
37
41
Eigen::MatrixXd Q = Eigen::MatrixXd::Zero (state_dim, state_dim);
42
+
43
+ // Control cost matrix R
44
+ // For single control dimension, this is a 1x1 matrix:
38
45
Eigen::MatrixXd R = 0.5 * Eigen::MatrixXd::Identity (control_dim, control_dim);
46
+
47
+ // Final state cost matrix Qf
48
+ // For example, a heavier penalty on final position/orientation
39
49
Eigen::MatrixXd Qf = Eigen::MatrixXd::Identity (state_dim, state_dim);
40
- Qf << 50.0 , 0.0 , 0.0 ,
41
- 0.0 , 50.0 , 0.0 ,
42
- 0.0 , 0.0 , 10.0 ;
43
- Qf = 0.5 * Qf;
50
+ Qf (0 ,0 ) = 50.0 ; // x
51
+ Qf (1 ,1 ) = 50.0 ; // y
52
+ Qf (2 ,2 ) = 10.0 ; // theta
53
+ Qf = 0.5 * Qf; // scaling
54
+
55
+ // Goal state
44
56
Eigen::VectorXd goal_state (state_dim);
45
- goal_state << 2.0 , 2.0 , M_PI/ 2.0 ;
57
+ goal_state << 2.0 , 2.0 , M_PI / 2.0 ;
46
58
47
- // Create an empty vector of Eigen::VectorXd
59
+ // Create an empty reference-state sequence (if needed for time-varying references)
48
60
std::vector<Eigen::VectorXd> empty_reference_states;
49
- auto objective = std::make_unique<cddp::QuadraticObjective>(Q, R, Qf, goal_state, empty_reference_states, timestep);
50
61
51
- // Initial and target states
62
+ // Build the quadratic objective
63
+ auto objective = std::make_unique<cddp::QuadraticObjective>(
64
+ Q, R, Qf, goal_state, empty_reference_states, timestep);
65
+
66
+ // Initial state
52
67
Eigen::VectorXd initial_state (state_dim);
53
- initial_state << 0.0 , 0.0 , M_PI/ 4.0 ;
68
+ initial_state << 0.0 , 0.0 , M_PI / 4.0 ;
54
69
55
70
// Create CDDP solver
56
71
cddp::CDDP cddp_solver (initial_state, goal_state, horizon, timestep);
57
72
cddp_solver.setDynamicalSystem (std::move (system));
58
73
cddp_solver.setObjective (std::move (objective));
59
74
60
- // Define constraints
75
+ // Define box constraints on control (here, single dimension: -pi to pi)
61
76
Eigen::VectorXd control_lower_bound (control_dim);
62
- control_lower_bound << -1.0 , -M_PI;
63
77
Eigen::VectorXd control_upper_bound (control_dim);
64
- control_upper_bound << 1.0 , M_PI;
65
-
78
+ control_lower_bound << -M_PI; // min turn rate
79
+ control_upper_bound << M_PI; // max turn rate
80
+
66
81
// Add the constraint to the solver
67
- cddp_solver.addConstraint (std::string (" ControlBoxConstraint" ), std::make_unique<cddp::ControlBoxConstraint>(control_lower_bound, control_upper_bound));
82
+ cddp_solver.addConstraint (
83
+ " ControlBoxConstraint" ,
84
+ std::make_unique<cddp::ControlBoxConstraint>(control_lower_bound, control_upper_bound));
85
+
86
+ // (Optional) retrieve the constraint object
68
87
auto constraint = cddp_solver.getConstraint <cddp::ControlBoxConstraint>(" ControlBoxConstraint" );
69
88
70
- // Set options
89
+ // Set CDDP options
71
90
cddp::CDDPOptions options;
72
- options.max_iterations = 10 ;
91
+ options.max_iterations = 10 ; // for demonstration
73
92
options.barrier_coeff = 1e-2 ;
74
93
options.barrier_factor = 0.1 ;
75
94
cddp_solver.setOptions (options);
76
95
77
- // Set initial trajectory
96
+ // Set an initial guess for the trajectory
97
+ // States (X) is horizon+1 in length, each dimension: 3
98
+ // Controls (U) is horizon in length, each dimension: 1
78
99
std::vector<Eigen::VectorXd> X (horizon + 1 , Eigen::VectorXd::Zero (state_dim));
79
- std::vector<Eigen::VectorXd> U (horizon, Eigen::VectorXd::Zero (control_dim));
100
+ std::vector<Eigen::VectorXd> U (horizon, Eigen::VectorXd::Zero (control_dim));
80
101
cddp_solver.setInitialTrajectory (X, U);
81
102
82
103
// Solve the problem
83
- // cddp::CDDPSolution solution = cddp_solver.solve( "CLCDDP");
104
+ // Possible algorithms: "CLCDDP", "LogCDDP", etc.
84
105
cddp::CDDPSolution solution = cddp_solver.solve (" LogCDDP" );
85
106
86
- // Extract solution
87
- auto X_sol = solution.state_sequence ; // size: horizon + 1
107
+ // Extract the solution sequences
108
+ auto X_sol = solution.state_sequence ; // size: horizon + 1
88
109
auto U_sol = solution.control_sequence ; // size: horizon
89
- auto t_sol = solution.time_sequence ; // size: horizon + 1
110
+ auto t_sol = solution.time_sequence ; // size: horizon + 1
90
111
91
- // Create directory for saving plot (if it doesn't exist)
112
+ // Create directory for saving plots (if it doesn't exist)
92
113
const std::string plotDirectory = " ../results/tests" ;
93
114
if (!fs::exists (plotDirectory)) {
94
- fs::create_directory (plotDirectory);
115
+ fs::create_directories (plotDirectory);
95
116
}
96
117
97
- // Plot the solution (x-y plane)
118
+ // Gather data for plotting
98
119
std::vector<double > x_arr, y_arr, theta_arr;
99
120
for (const auto & x : X_sol) {
100
121
x_arr.push_back (x (0 ));
101
122
y_arr.push_back (x (1 ));
102
123
theta_arr.push_back (x (2 ));
103
124
}
104
125
105
- // Plot the solution ( control inputs)
106
- std::vector<double > v_arr, omega_arr;
126
+ // For single-dim control: just store the steering rate
127
+ std::vector<double > omega_arr;
107
128
for (const auto & u : U_sol) {
108
- v_arr.push_back (u (0 ));
109
- omega_arr.push_back (u (1 ));
129
+ omega_arr.push_back (u (0 ));
110
130
}
111
131
112
- // Plot the solution by subplots
132
+ // Plot state trajectory & control
113
133
plt::subplot (2 , 1 , 1 );
114
134
plt::plot (x_arr, y_arr);
115
- plt::title (" State Trajectory" );
135
+ plt::title (" DubinsCar State Trajectory" );
116
136
plt::xlabel (" x" );
117
137
plt::ylabel (" y" );
118
138
119
139
plt::subplot (2 , 1 , 2 );
120
- plt::plot (v_arr);
121
140
plt::plot (omega_arr);
122
- plt::title (" Control Inputs " );
123
- plt::save (plotDirectory + " /dubincs_car_cddp_test .png" );
141
+ plt::title (" Steering Rate Control (omega) " );
142
+ plt::save (plotDirectory + " /dubins_car_cddp_test .png" );
124
143
125
- // Create figure and axes
144
+ // Optional: Generate an animation
145
+ // (requires multiple frames, so you may want to store and
146
+ // convert them to a GIF afterward).
126
147
plt::figure_size (800 , 600 );
127
- plt::title (" Dubins Car Trajectory" );
148
+ plt::title (" DubinsCar Trajectory" );
128
149
plt::xlabel (" x" );
129
150
plt::ylabel (" y" );
130
- plt::xlim (-1 , 3 ); // Adjust limits as needed
131
- plt::ylim (-1 , 3 ); // Adjust limits as needed
151
+ plt::xlim (-1 , 3 );
152
+ plt::ylim (-1 , 3 );
132
153
133
154
// Car dimensions
134
155
double car_length = 0.2 ;
135
- double car_width = 0.1 ;
136
-
137
- // Animation function
138
- for (int i = 0 ; i < X_sol.size (); ++i) {
156
+ double car_width = 0.1 ;
139
157
158
+ // Animation loop
159
+ for (int i = 0 ; i < static_cast <int >(X_sol.size ()); ++i) {
140
160
if (i % 5 == 0 ) {
141
- // Clear previous plot
142
- plt::clf ();
161
+ plt::clf ();
143
162
144
- // Plot car as a box with heading
145
- double x = x_arr[i];
146
- double y = y_arr[i];
163
+ // Current pose
164
+ double x = x_arr[i];
165
+ double y = y_arr[i];
147
166
double theta = theta_arr[i];
148
-
149
- // Calculate car corner points
150
- std::vector<double > car_x (5 );
151
- std::vector<double > car_y (5 );
152
167
153
- car_x[ 0 ] = x + car_length/ 2 * cos (theta) - car_width/ 2 * sin (theta);
154
- car_y[ 0 ] = y + car_length/ 2 * sin (theta) + car_width/ 2 * cos (theta );
168
+ // Compute corners of the car rectangle
169
+ std::vector< double > car_x ( 5 ), car_y ( 5 );
155
170
156
- car_x[1 ] = x + car_length/2 * cos (theta) + car_width/2 * sin (theta);
157
- car_y[1 ] = y + car_length/2 * sin (theta) - car_width/2 * cos (theta);
171
+ // Front-left corner
172
+ car_x[0 ] = x + car_length/2.0 * cos (theta) - car_width/2.0 * sin (theta);
173
+ car_y[0 ] = y + car_length/2.0 * sin (theta) + car_width/2.0 * cos (theta);
158
174
159
- car_x[2 ] = x - car_length/2 * cos (theta) + car_width/2 * sin (theta);
160
- car_y[2 ] = y - car_length/2 * sin (theta) - car_width/2 * cos (theta);
175
+ // Front-right corner
176
+ car_x[1 ] = x + car_length/2.0 * cos (theta) + car_width/2.0 * sin (theta);
177
+ car_y[1 ] = y + car_length/2.0 * sin (theta) - car_width/2.0 * cos (theta);
161
178
162
- car_x[3 ] = x - car_length/2 * cos (theta) - car_width/2 * sin (theta);
163
- car_y[3 ] = y - car_length/2 * sin (theta) + car_width/2 * cos (theta);
179
+ // Rear-right corner
180
+ car_x[2 ] = x - car_length/2.0 * cos (theta) + car_width/2.0 * sin (theta);
181
+ car_y[2 ] = y - car_length/2.0 * sin (theta) - car_width/2.0 * cos (theta);
164
182
165
- car_x[4 ] = car_x[0 ]; // Close the shape
183
+ // Rear-left corner
184
+ car_x[3 ] = x - car_length/2.0 * cos (theta) - car_width/2.0 * sin (theta);
185
+ car_y[3 ] = y - car_length/2.0 * sin (theta) + car_width/2.0 * cos (theta);
186
+
187
+ // Close the shape
188
+ car_x[4 ] = car_x[0 ];
166
189
car_y[4 ] = car_y[0 ];
167
190
168
191
// Plot the car
169
192
plt::plot (car_x, car_y, " k-" );
170
193
171
- // Plot trajectory up to current point
172
- plt::plot (std::vector<double >(x_arr.begin (), x_arr.begin () + i + 1 ),
173
- std::vector<double >(y_arr.begin (), y_arr.begin () + i + 1 ), " b-" );
174
-
175
- // Add plot title
176
- plt::title (" Dubins Car Trajectory" );
194
+ // Plot the trajectory so far
195
+ plt::plot (std::vector<double >(x_arr.begin (), x_arr.begin () + i + 1 ),
196
+ std::vector<double >(y_arr.begin (), y_arr.begin () + i + 1 ),
197
+ " b-" );
177
198
178
- // Set labels
199
+ // Title and axes
200
+ plt::title (" DubinsCar Trajectory" );
179
201
plt::xlabel (" x" );
180
202
plt::ylabel (" y" );
203
+ plt::xlim (-1 , 3 );
204
+ plt::ylim (-1 , 3 );
181
205
182
- // Adjust limits as needed
183
- plt::xlim (-1 , 3 );
184
- plt::ylim (-1 , 3 );
185
-
186
- // Enable legend
187
- plt::legend ();
188
-
189
- // Save current frame as an image
206
+ // Save frame
190
207
std::string filename = plotDirectory + " /dubins_car_frame_" + std::to_string (i) + " .png" ;
191
208
plt::save (filename);
192
-
193
- // Display plot continuously
194
- plt::pause (0.01 ); // Pause for a short time
195
209
210
+ // Brief pause for "animation" effect
211
+ plt::pause (0.01 );
196
212
}
197
- };
198
- }
213
+ }
199
214
200
- // Create gif from images using ImageMagick
201
- // Installation:
202
- // $ sudo apt-get install imagemagick
215
+ // Optionally, you can convert frames to a GIF via ImageMagick:
216
+ // convert -delay 100 ../results/tests/dubins_car_frame_*.png ../results/tests/dubins_car.gif
203
217
204
- // convert -delay 100 ../results/tests/dubins_car_frame_*.png ../results/tests/dubins_car.gif
218
+ return 0 ;
219
+ }
0 commit comments