43 #include <ilqgames/cost/curvature_cost.h> 44 #include <ilqgames/cost/final_time_cost.h> 45 #include <ilqgames/cost/locally_convex_proximity_cost.h> 46 #include <ilqgames/cost/nominal_path_length_cost.h> 47 #include <ilqgames/cost/proximity_cost.h> 48 #include <ilqgames/cost/quadratic_cost.h> 49 #include <ilqgames/cost/quadratic_polyline2_cost.h> 50 #include <ilqgames/cost/semiquadratic_cost.h> 51 #include <ilqgames/cost/semiquadratic_polyline2_cost.h> 52 #include <ilqgames/cost/weighted_convex_proximity_cost.h> 53 #include <ilqgames/dynamics/concatenated_dynamical_system.h> 54 #include <ilqgames/dynamics/single_player_car_6d.h> 55 #include <ilqgames/dynamics/single_player_unicycle_4d.h> 56 #include <ilqgames/examples/roundabout_lane_center.h> 57 #include <ilqgames/examples/roundabout_merging_example.h> 58 #include <ilqgames/geometry/polyline2.h> 59 #include <ilqgames/solver/ilq_solver.h> 60 #include <ilqgames/solver/lq_feedback_solver.h> 61 #include <ilqgames/solver/problem.h> 62 #include <ilqgames/solver/solver_params.h> 63 #include <ilqgames/utils/initialize_along_route.h> 64 #include <ilqgames/utils/solver_log.h> 65 #include <ilqgames/utils/strategy.h> 66 #include <ilqgames/utils/types.h> 77 static constexpr
float kOmegaCostWeight = 500.0;
78 static constexpr
float kACostWeight = 50.0;
79 static constexpr
float kJerkCostWeight = 5.0;
81 static constexpr
float kMaxVCostWeight = 1000.0;
82 static constexpr
float kNominalVCostWeight = 10.0;
84 static constexpr
float kLaneCostWeight = 25.0;
85 static constexpr
float kLaneBoundaryCostWeight = 100.0;
87 static constexpr
float kMinProximity = 6.0;
88 static constexpr
float kP1ProximityCostWeight = 100.0;
89 static constexpr
float kP2ProximityCostWeight = 100.0;
90 static constexpr
float kP3ProximityCostWeight = 100.0;
91 static constexpr
float kP4ProximityCostWeight = 100.0;
92 using ProxCost = ProximityCost;
94 static constexpr
bool kOrientedRight =
true;
97 static constexpr
float kLaneHalfWidth = 2.5;
100 static constexpr
float kP1MaxV = 12.0;
101 static constexpr
float kP2MaxV = 12.0;
102 static constexpr
float kP3MaxV = 12.0;
103 static constexpr
float kP4MaxV = 12.0;
104 static constexpr
float kMinV = 1.0;
106 static constexpr
float kP1NominalV = 10.0;
107 static constexpr
float kP2NominalV = 10.0;
108 static constexpr
float kP3NominalV = 10.0;
109 static constexpr
float kP4NominalV = 10.0;
112 static constexpr
float kP1InitialDistanceToRoundabout = 25.0;
113 static constexpr
float kP2InitialDistanceToRoundabout = 10.0;
114 static constexpr
float kP3InitialDistanceToRoundabout = 25.0;
115 static constexpr
float kP4InitialDistanceToRoundabout = 10.0;
117 static constexpr
float kP1InitialSpeed = 3.0;
118 static constexpr
float kP2InitialSpeed = 2.0;
119 static constexpr
float kP3InitialSpeed = 3.0;
120 static constexpr
float kP4InitialSpeed = 2.0;
123 static constexpr
float kInterAxleDistance = 4.0;
124 using P1 = SinglePlayerCar6D;
125 using P2 = SinglePlayerCar6D;
126 using P3 = SinglePlayerCar6D;
127 using P4 = SinglePlayerCar6D;
129 static const Dimension kP1XIdx = P1::kPxIdx;
130 static const Dimension kP1YIdx = P1::kPyIdx;
131 static const Dimension kP1HeadingIdx = P1::kThetaIdx;
132 static const Dimension kP1VIdx = P1::kVIdx;
133 static const Dimension kP1AIdx = P1::kAIdx;
135 static const Dimension kP2XIdx = P1::kNumXDims + P2::kPxIdx;
136 static const Dimension kP2YIdx = P1::kNumXDims + P2::kPyIdx;
137 static const Dimension kP2HeadingIdx = P1::kNumXDims + P2::kThetaIdx;
138 static const Dimension kP2VIdx = P1::kNumXDims + P2::kVIdx;
139 static const Dimension kP2AIdx = P1::kNumXDims + P2::kAIdx;
141 static const Dimension kP3XIdx = P1::kNumXDims + P2::kNumXDims + P3::kPxIdx;
142 static const Dimension kP3YIdx = P1::kNumXDims + P2::kNumXDims + P3::kPyIdx;
143 static const Dimension kP3HeadingIdx =
144 P1::kNumXDims + P2::kNumXDims + P3::kThetaIdx;
145 static const Dimension kP3VIdx = P1::kNumXDims + P2::kNumXDims + P3::kVIdx;
146 static const Dimension kP3AIdx = P1::kNumXDims + P2::kNumXDims + P3::kAIdx;
148 static const Dimension kP4XIdx =
149 P1::kNumXDims + P2::kNumXDims + P3::kNumXDims + P4::kPxIdx;
150 static const Dimension kP4YIdx =
151 P1::kNumXDims + P2::kNumXDims + P3::kNumXDims + P4::kPyIdx;
152 static const Dimension kP4HeadingIdx =
153 P1::kNumXDims + P2::kNumXDims + P3::kNumXDims + P4::kThetaIdx;
154 static const Dimension kP4VIdx =
155 P1::kNumXDims + P2::kNumXDims + P3::kNumXDims + P4::kVIdx;
156 static const Dimension kP4AIdx =
157 P1::kNumXDims + P2::kNumXDims + P3::kNumXDims + P4::kAIdx;
160 static const Dimension kP1OmegaIdx = 0;
161 static const Dimension kP1JerkIdx = 1;
162 static const Dimension kP2OmegaIdx = 0;
163 static const Dimension kP2JerkIdx = 1;
164 static const Dimension kP3OmegaIdx = 0;
165 static const Dimension kP3JerkIdx = 1;
166 static const Dimension kP4OmegaIdx = 0;
167 static const Dimension kP4JerkIdx = 1;
170 static constexpr
float kAngleOffset = M_PI_2 * 0.5;
171 static constexpr
float kWedgeSize = M_PI;
172 const std::vector<float> angles = {kAngleOffset,
173 kAngleOffset + 2.0 * M_PI / 4.0,
174 kAngleOffset + 2.0 * 2.0 * M_PI / 4.0,
175 kAngleOffset + 3.0 * 2.0 * M_PI / 4.0};
176 const Polyline2 lane1(RoundaboutLaneCenter(angles[0], angles[0] + kWedgeSize,
177 kP1InitialDistanceToRoundabout));
178 const Polyline2 lane2(RoundaboutLaneCenter(angles[1], angles[1] + kWedgeSize,
179 kP2InitialDistanceToRoundabout));
180 const Polyline2 lane3(RoundaboutLaneCenter(angles[2], angles[2] + kWedgeSize,
181 kP3InitialDistanceToRoundabout));
182 const Polyline2 lane4(RoundaboutLaneCenter(angles[3], angles[3] + kWedgeSize,
183 kP4InitialDistanceToRoundabout));
187 void RoundaboutMergingExample::ConstructDynamics() {
188 dynamics_.reset(
new ConcatenatedDynamicalSystem(
189 {std::make_shared<P1>(kInterAxleDistance),
190 std::make_shared<P2>(kInterAxleDistance),
191 std::make_shared<P3>(kInterAxleDistance),
192 std::make_shared<P4>(kInterAxleDistance)}));
195 void RoundaboutMergingExample::ConstructInitialState() {
196 x0_ = VectorXf::Zero(dynamics_->XDim());
197 x0_(kP1XIdx) = lane1.Segments()[0].FirstPoint().x();
198 x0_(kP1YIdx) = lane1.Segments()[0].FirstPoint().y();
199 x0_(kP1HeadingIdx) = lane1.Segments()[0].Heading();
200 x0_(kP1VIdx) = kP1InitialSpeed;
201 x0_(kP2XIdx) = lane2.Segments()[0].FirstPoint().x();
202 x0_(kP2YIdx) = lane2.Segments()[0].FirstPoint().y();
203 x0_(kP2HeadingIdx) = lane2.Segments()[0].Heading();
204 x0_(kP2VIdx) = kP2InitialSpeed;
205 x0_(kP3XIdx) = lane3.Segments()[0].FirstPoint().x();
206 x0_(kP3YIdx) = lane3.Segments()[0].FirstPoint().y();
207 x0_(kP3HeadingIdx) = lane3.Segments()[0].Heading();
208 x0_(kP3VIdx) = kP3InitialSpeed;
209 x0_(kP4XIdx) = lane4.Segments()[0].FirstPoint().x();
210 x0_(kP4YIdx) = lane4.Segments()[0].FirstPoint().y();
211 x0_(kP4HeadingIdx) = lane4.Segments()[0].Heading();
212 x0_(kP4VIdx) = kP4InitialSpeed;
215 void RoundaboutMergingExample::ConstructInitialOperatingPoint() {
225 Problem::ConstructInitialOperatingPoint();
228 void RoundaboutMergingExample::ConstructPlayerCosts() {
230 player_costs_.emplace_back(
"P1");
231 player_costs_.emplace_back(
"P2");
232 player_costs_.emplace_back(
"P3");
233 player_costs_.emplace_back(
"P4");
234 auto& p1_cost = player_costs_[0];
235 auto& p2_cost = player_costs_[1];
236 auto& p3_cost = player_costs_[2];
237 auto& p4_cost = player_costs_[3];
240 const std::shared_ptr<QuadraticPolyline2Cost> p1_lane_cost(
241 new QuadraticPolyline2Cost(kLaneCostWeight, lane1, {kP1XIdx, kP1YIdx},
243 const std::shared_ptr<SemiquadraticPolyline2Cost> p1_lane_r_cost(
244 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane1,
245 {kP1XIdx, kP1YIdx}, kLaneHalfWidth,
246 kOrientedRight,
"LaneRightBoundary"));
247 const std::shared_ptr<SemiquadraticPolyline2Cost> p1_lane_l_cost(
248 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane1,
249 {kP1XIdx, kP1YIdx}, -kLaneHalfWidth,
250 !kOrientedRight,
"LaneLeftBoundary"));
251 p1_cost.AddStateCost(p1_lane_cost);
252 p1_cost.AddStateCost(p1_lane_r_cost);
253 p1_cost.AddStateCost(p1_lane_l_cost);
255 const std::shared_ptr<QuadraticPolyline2Cost> p2_lane_cost(
256 new QuadraticPolyline2Cost(kLaneCostWeight, lane2, {kP2XIdx, kP2YIdx},
258 const std::shared_ptr<SemiquadraticPolyline2Cost> p2_lane_r_cost(
259 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane2,
260 {kP2XIdx, kP2YIdx}, kLaneHalfWidth,
261 kOrientedRight,
"LaneRightBoundary"));
262 const std::shared_ptr<SemiquadraticPolyline2Cost> p2_lane_l_cost(
263 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane2,
264 {kP2XIdx, kP2YIdx}, -kLaneHalfWidth,
265 !kOrientedRight,
"LaneLeftBoundary"));
266 p2_cost.AddStateCost(p2_lane_cost);
267 p2_cost.AddStateCost(p2_lane_r_cost);
268 p2_cost.AddStateCost(p2_lane_l_cost);
270 const std::shared_ptr<QuadraticPolyline2Cost> p3_lane_cost(
271 new QuadraticPolyline2Cost(kLaneCostWeight, lane3, {kP3XIdx, kP3YIdx},
273 const std::shared_ptr<SemiquadraticPolyline2Cost> p3_lane_r_cost(
274 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane3,
275 {kP3XIdx, kP3YIdx}, kLaneHalfWidth,
276 kOrientedRight,
"LaneRightBoundary"));
277 const std::shared_ptr<SemiquadraticPolyline2Cost> p3_lane_l_cost(
278 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane3,
279 {kP3XIdx, kP3YIdx}, -kLaneHalfWidth,
280 !kOrientedRight,
"LaneLeftBoundary"));
281 p3_cost.AddStateCost(p3_lane_cost);
282 p3_cost.AddStateCost(p3_lane_r_cost);
283 p3_cost.AddStateCost(p3_lane_l_cost);
285 const std::shared_ptr<QuadraticPolyline2Cost> p4_lane_cost(
286 new QuadraticPolyline2Cost(kLaneCostWeight, lane4, {kP4XIdx, kP4YIdx},
288 const std::shared_ptr<SemiquadraticPolyline2Cost> p4_lane_r_cost(
289 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane4,
290 {kP4XIdx, kP4YIdx}, kLaneHalfWidth,
291 kOrientedRight,
"LaneRightBoundary"));
292 const std::shared_ptr<SemiquadraticPolyline2Cost> p4_lane_l_cost(
293 new SemiquadraticPolyline2Cost(kLaneBoundaryCostWeight, lane4,
294 {kP4XIdx, kP4YIdx}, -kLaneHalfWidth,
295 !kOrientedRight,
"LaneLeftBoundary"));
296 p4_cost.AddStateCost(p4_lane_cost);
297 p4_cost.AddStateCost(p4_lane_r_cost);
298 p4_cost.AddStateCost(p4_lane_l_cost);
301 const auto p1_min_v_cost = std::make_shared<SemiquadraticCost>(
302 kMaxVCostWeight, kP1VIdx, kMinV, !kOrientedRight,
"MinV");
303 const auto p1_max_v_cost = std::make_shared<SemiquadraticCost>(
304 kMaxVCostWeight, kP1VIdx, kP1MaxV, kOrientedRight,
"MaxV");
305 const auto p1_nominal_v_cost = std::make_shared<QuadraticCost>(
306 kNominalVCostWeight, kP1VIdx, kP1NominalV,
"NominalV");
307 p1_cost.AddStateCost(p1_min_v_cost);
308 p1_cost.AddStateCost(p1_max_v_cost);
309 p1_cost.AddStateCost(p1_nominal_v_cost);
311 const auto p2_min_v_cost = std::make_shared<SemiquadraticCost>(
312 kMaxVCostWeight, kP2VIdx, kMinV, !kOrientedRight,
"MinV");
313 const auto p2_max_v_cost = std::make_shared<SemiquadraticCost>(
314 kMaxVCostWeight, kP2VIdx, kP2MaxV, kOrientedRight,
"MaxV");
315 const auto p2_nominal_v_cost = std::make_shared<QuadraticCost>(
316 kNominalVCostWeight, kP2VIdx, kP2NominalV,
"NominalV");
317 p2_cost.AddStateCost(p2_min_v_cost);
318 p2_cost.AddStateCost(p2_max_v_cost);
319 p2_cost.AddStateCost(p2_nominal_v_cost);
321 const auto p3_min_v_cost = std::make_shared<SemiquadraticCost>(
322 kMaxVCostWeight, kP3VIdx, kMinV, !kOrientedRight,
"MinV");
323 const auto p3_max_v_cost = std::make_shared<SemiquadraticCost>(
324 kMaxVCostWeight, kP3VIdx, kP3MaxV, kOrientedRight,
"MaxV");
325 const auto p3_nominal_v_cost = std::make_shared<QuadraticCost>(
326 kNominalVCostWeight, kP3VIdx, kP3NominalV,
"NominalV");
327 p3_cost.AddStateCost(p3_min_v_cost);
328 p3_cost.AddStateCost(p3_max_v_cost);
329 p3_cost.AddStateCost(p3_nominal_v_cost);
331 const auto p4_min_v_cost = std::make_shared<SemiquadraticCost>(
332 kMaxVCostWeight, kP4VIdx, kMinV, !kOrientedRight,
"MinV");
333 const auto p4_max_v_cost = std::make_shared<SemiquadraticCost>(
334 kMaxVCostWeight, kP4VIdx, kP4MaxV, kOrientedRight,
"MaxV");
335 const auto p4_nominal_v_cost = std::make_shared<QuadraticCost>(
336 kNominalVCostWeight, kP4VIdx, kP4NominalV,
"NominalV");
337 p4_cost.AddStateCost(p4_min_v_cost);
338 p4_cost.AddStateCost(p4_max_v_cost);
339 p4_cost.AddStateCost(p4_nominal_v_cost);
342 const auto p1_a_cost = std::make_shared<QuadraticCost>(kACostWeight, kP1AIdx,
343 0.0,
"Acceleration");
344 p1_cost.AddStateCost(p1_a_cost);
345 const auto p2_a_cost = std::make_shared<QuadraticCost>(kACostWeight, kP1AIdx,
346 0.0,
"Acceleration");
347 p2_cost.AddStateCost(p2_a_cost);
348 const auto p3_a_cost = std::make_shared<QuadraticCost>(kACostWeight, kP1AIdx,
349 0.0,
"Acceleration");
350 p3_cost.AddStateCost(p3_a_cost);
351 const auto p4_a_cost = std::make_shared<QuadraticCost>(kACostWeight, kP1AIdx,
352 0.0,
"Acceleration");
353 p4_cost.AddStateCost(p4_a_cost);
356 const auto p1_omega_cost = std::make_shared<QuadraticCost>(
357 kOmegaCostWeight, kP1OmegaIdx, 0.0,
"Steering");
358 const auto p1_j_cost =
359 std::make_shared<QuadraticCost>(kJerkCostWeight, kP1JerkIdx, 0.0,
"Jerk");
360 p1_cost.AddControlCost(0, p1_omega_cost);
361 p1_cost.AddControlCost(0, p1_j_cost);
363 const auto p2_omega_cost = std::make_shared<QuadraticCost>(
364 kOmegaCostWeight, kP2OmegaIdx, 0.0,
"Steering");
365 const auto p2_j_cost =
366 std::make_shared<QuadraticCost>(kJerkCostWeight, kP2JerkIdx, 0.0,
"Jerk");
367 p2_cost.AddControlCost(1, p2_omega_cost);
368 p2_cost.AddControlCost(1, p2_j_cost);
370 const auto p3_omega_cost = std::make_shared<QuadraticCost>(
371 kOmegaCostWeight, kP3OmegaIdx, 0.0,
"Steering");
372 const auto p3_j_cost =
373 std::make_shared<QuadraticCost>(kJerkCostWeight, kP3JerkIdx, 0.0,
"Jerk");
374 p3_cost.AddControlCost(2, p3_omega_cost);
375 p3_cost.AddControlCost(2, p3_j_cost);
377 const auto p4_omega_cost = std::make_shared<QuadraticCost>(
378 kOmegaCostWeight, kP4OmegaIdx, 0.0,
"Steering");
379 const auto p4_j_cost =
380 std::make_shared<QuadraticCost>(kJerkCostWeight, kP4JerkIdx, 0.0,
"Jerk");
381 p4_cost.AddControlCost(3, p4_omega_cost);
382 p4_cost.AddControlCost(3, p4_j_cost);
385 const std::shared_ptr<ProxCost> p1p2_proximity_cost(
386 new ProxCost(kP1ProximityCostWeight, {kP1XIdx, kP1YIdx},
387 {kP2XIdx, kP2YIdx}, kMinProximity,
"ProximityP2"));
388 const std::shared_ptr<ProxCost> p1p3_proximity_cost(
389 new ProxCost(kP1ProximityCostWeight, {kP1XIdx, kP1YIdx},
390 {kP3XIdx, kP3YIdx}, kMinProximity,
"ProximityP3"));
391 const std::shared_ptr<ProxCost> p1p4_proximity_cost(
392 new ProxCost(kP1ProximityCostWeight, {kP1XIdx, kP1YIdx},
393 {kP4XIdx, kP4YIdx}, kMinProximity,
"ProximityP4"));
394 p1_cost.AddStateCost(p1p2_proximity_cost);
396 p1_cost.AddStateCost(p1p4_proximity_cost);
398 const std::shared_ptr<ProxCost> p2p1_proximity_cost(
399 new ProxCost(kP2ProximityCostWeight, {kP2XIdx, kP2YIdx},
400 {kP1XIdx, kP1YIdx}, kMinProximity,
"ProximityP1"));
401 const std::shared_ptr<ProxCost> p2p3_proximity_cost(
402 new ProxCost(kP2ProximityCostWeight, {kP2XIdx, kP2YIdx},
403 {kP3XIdx, kP3YIdx}, kMinProximity,
"ProximityP3"));
404 const std::shared_ptr<ProxCost> p2p4_proximity_cost(
405 new ProxCost(kP2ProximityCostWeight, {kP2XIdx, kP2YIdx},
406 {kP4XIdx, kP4YIdx}, kMinProximity,
"ProximityP4"));
407 p2_cost.AddStateCost(p2p1_proximity_cost);
408 p2_cost.AddStateCost(p2p3_proximity_cost);
411 const std::shared_ptr<ProxCost> p3p1_proximity_cost(
412 new ProxCost(kP3ProximityCostWeight, {kP3XIdx, kP3YIdx},
413 {kP1XIdx, kP1YIdx}, kMinProximity,
"ProximityP1"));
414 const std::shared_ptr<ProxCost> p3p2_proximity_cost(
415 new ProxCost(kP3ProximityCostWeight, {kP3XIdx, kP3YIdx},
416 {kP2XIdx, kP2YIdx}, kMinProximity,
"ProximityP2"));
417 const std::shared_ptr<ProxCost> p3p4_proximity_cost(
418 new ProxCost(kP3ProximityCostWeight, {kP3XIdx, kP3YIdx},
419 {kP4XIdx, kP4YIdx}, kMinProximity,
"ProximityP4"));
421 p3_cost.AddStateCost(p3p2_proximity_cost);
422 p3_cost.AddStateCost(p3p4_proximity_cost);
424 const std::shared_ptr<ProxCost> p4p1_proximity_cost(
425 new ProxCost(kP4ProximityCostWeight, {kP4XIdx, kP4YIdx},
426 {kP1XIdx, kP1YIdx}, kMinProximity,
"ProximityP1"));
427 const std::shared_ptr<ProxCost> p4p2_proximity_cost(
428 new ProxCost(kP4ProximityCostWeight, {kP4XIdx, kP4YIdx},
429 {kP2XIdx, kP2YIdx}, kMinProximity,
"ProximityP2"));
430 const std::shared_ptr<ProxCost> p4p3_proximity_cost(
431 new ProxCost(kP4ProximityCostWeight, {kP4XIdx, kP4YIdx},
432 {kP3XIdx, kP3YIdx}, kMinProximity,
"ProximityP3"));
433 p4_cost.AddStateCost(p4p1_proximity_cost);
435 p4_cost.AddStateCost(p4p3_proximity_cost);
438 inline std::vector<float> RoundaboutMergingExample::Xs(
439 const VectorXf& x)
const {
440 return {x(kP1XIdx), x(kP2XIdx), x(kP3XIdx), x(kP4XIdx)};
443 inline std::vector<float> RoundaboutMergingExample::Ys(
444 const VectorXf& x)
const {
445 return {x(kP1YIdx), x(kP2YIdx), x(kP3YIdx), x(kP4YIdx)};
448 inline std::vector<float> RoundaboutMergingExample::Thetas(
449 const VectorXf& x)
const {
450 return {x(kP1HeadingIdx), x(kP2HeadingIdx), x(kP3HeadingIdx),