ilqgames
A new real-time solver for large-scale differential games.
three_player_collision_avoidance_reachability_example.cpp
1 /*
2  * Copyright (c) 2020, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  */
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 //
39 // Three player collision-avoidance example using approximate HJ reachability.
40 //
41 ///////////////////////////////////////////////////////////////////////////////
42 
43 #include <ilqgames/constraint/single_dimension_constraint.h>
44 #include <ilqgames/cost/extreme_value_cost.h>
45 #include <ilqgames/cost/quadratic_cost.h>
46 #include <ilqgames/cost/signed_distance_cost.h>
47 #include <ilqgames/dynamics/concatenated_dynamical_system.h>
48 #include <ilqgames/dynamics/single_player_car_5d.h>
49 #include <ilqgames/examples/three_player_collision_avoidance_reachability_example.h>
50 #include <ilqgames/geometry/draw_shapes.h>
51 #include <ilqgames/geometry/polyline2.h>
52 #include <ilqgames/solver/ilq_solver.h>
53 #include <ilqgames/solver/problem.h>
54 #include <ilqgames/solver/solver_params.h>
55 #include <ilqgames/utils/types.h>
56 
57 #include <math.h>
58 #include <memory>
59 #include <vector>
60 
61 // Initial state command-line flags.
62 DEFINE_double(d0, 5.0, "Initial distance from the origin (m).");
63 DEFINE_double(v0, 5.0, "Initial speed (m/s).");
64 
65 // Buffer for the signed distance cost.
66 DEFINE_double(buffer, 3.0, "Nominal signed distance cost (m).");
67 
68 namespace ilqgames {
69 
70 namespace {
71 
72 // Input contraints and cost
73 static constexpr float kOmegaMax = 1.0;
74 static constexpr float kAMax = 0.1;
75 static constexpr float kControlCostWeight = 0.1;
76 
77 // State dimensions.
78 using P1 = SinglePlayerCar5D;
79 using P2 = SinglePlayerCar5D;
80 using P3 = SinglePlayerCar5D;
81 static constexpr float kInterAxleDistance = 4.0;
82 
83 static const Dimension kP1XIdx = P1::kPxIdx;
84 static const Dimension kP1YIdx = P1::kPyIdx;
85 static const Dimension kP1HeadingIdx = P1::kThetaIdx;
86 static const Dimension kP1VIdx = P1::kVIdx;
87 
88 static const Dimension kP2XIdx = P1::kNumXDims + P2::kPxIdx;
89 static const Dimension kP2YIdx = P1::kNumXDims + P2::kPyIdx;
90 static const Dimension kP2HeadingIdx = P1::kNumXDims + P2::kThetaIdx;
91 static const Dimension kP2VIdx = P1::kNumXDims + P2::kVIdx;
92 
93 static const Dimension kP3XIdx = P1::kNumXDims + P2::kNumXDims + P3::kPxIdx;
94 static const Dimension kP3YIdx = P1::kNumXDims + P2::kNumXDims + P3::kPyIdx;
95 static const Dimension kP3HeadingIdx =
96  P1::kNumXDims + P2::kNumXDims + P3::kThetaIdx;
97 static const Dimension kP3VIdx = P1::kNumXDims + P2::kNumXDims + P3::kVIdx;
98 
99 } // anonymous namespace
100 
101 void ThreePlayerCollisionAvoidanceReachabilityExample::ConstructDynamics() {
102  dynamics_.reset(new ConcatenatedDynamicalSystem(
103  {std::make_shared<P1>(kInterAxleDistance),
104  std::make_shared<P2>(kInterAxleDistance),
105  std::make_shared<P3>(kInterAxleDistance)}));
106 }
107 
108 void ThreePlayerCollisionAvoidanceReachabilityExample::ConstructInitialState() {
109  // Set up initial state.
110  constexpr float kAnglePerturbation = 0.1; // rad
111  x0_ = VectorXf::Zero(dynamics_->XDim());
112  x0_(kP1XIdx) = FLAGS_d0;
113  x0_(kP1YIdx) = 0.0;
114  x0_(kP1HeadingIdx) = -M_PI + kAnglePerturbation;
115  x0_(kP1VIdx) = FLAGS_v0;
116  x0_(kP2XIdx) = -0.5 * FLAGS_d0;
117  x0_(kP2YIdx) = 0.5 * std::sqrt(3.0) * FLAGS_d0;
118  x0_(kP2HeadingIdx) = -M_PI / 3.0 + kAnglePerturbation;
119  x0_(kP2VIdx) = FLAGS_v0;
120  x0_(kP3XIdx) = -0.5 * FLAGS_d0;
121  x0_(kP3YIdx) = -0.5 * std::sqrt(3.0) * FLAGS_d0;
122  x0_(kP3HeadingIdx) = M_PI / 3.0 + kAnglePerturbation;
123  x0_(kP3VIdx) = FLAGS_v0;
124 }
125 
126 void ThreePlayerCollisionAvoidanceReachabilityExample::ConstructPlayerCosts() {
127  // Set up costs for all players.
128  player_costs_.emplace_back("P1");
129  player_costs_.emplace_back("P2");
130  player_costs_.emplace_back("P3");
131  auto& p1_cost = player_costs_[0];
132  auto& p2_cost = player_costs_[1];
133  auto& p3_cost = player_costs_[2];
134 
135  // Quadratic control costs.
136  const auto control_cost = std::make_shared<QuadraticCost>(
137  kControlCostWeight, -1, 0.0, "ControlCost");
138  p1_cost.AddControlCost(0, control_cost);
139  p2_cost.AddControlCost(1, control_cost);
140  p3_cost.AddControlCost(2, control_cost);
141 
142  // Constrain control input.
143  const auto p1_omega_max_constraint =
144  std::make_shared<SingleDimensionConstraint>(
145  P1::kOmegaIdx, kOmegaMax, true, "Omega Constraint (Max)");
146  const auto p1_omega_min_constraint =
147  std::make_shared<SingleDimensionConstraint>(
148  P1::kOmegaIdx, -kOmegaMax, false, "Omega Constraint (Min)");
149  const auto p1_a_max_constraint = std::make_shared<SingleDimensionConstraint>(
150  P1::kAIdx, kAMax, true, "Acceleration Constraint (Max)");
151  const auto p1_a_min_constraint = std::make_shared<SingleDimensionConstraint>(
152  P1::kAIdx, -kAMax, false, "Acceleration Constraint (Min)");
153  p1_cost.AddControlConstraint(0, p1_omega_max_constraint);
154  p1_cost.AddControlConstraint(0, p1_omega_min_constraint);
155  p1_cost.AddControlConstraint(0, p1_a_max_constraint);
156  p1_cost.AddControlConstraint(0, p1_a_min_constraint);
157 
158  const auto p2_omega_max_constraint =
159  std::make_shared<SingleDimensionConstraint>(
160  P2::kOmegaIdx, kOmegaMax, true, "Omega Constraint (Max)");
161  const auto p2_omega_min_constraint =
162  std::make_shared<SingleDimensionConstraint>(
163  P2::kOmegaIdx, -kOmegaMax, false, "Omega Constraint (Min)");
164  const auto p2_a_max_constraint = std::make_shared<SingleDimensionConstraint>(
165  P2::kAIdx, kAMax, true, "Acceleration Constraint (Max)");
166  const auto p2_a_min_constraint = std::make_shared<SingleDimensionConstraint>(
167  P2::kAIdx, -kAMax, false, "Acceleration Constraint (Min)");
168  p2_cost.AddControlConstraint(1, p2_omega_max_constraint);
169  p2_cost.AddControlConstraint(1, p2_omega_min_constraint);
170  p2_cost.AddControlConstraint(1, p2_a_max_constraint);
171  p2_cost.AddControlConstraint(1, p2_a_min_constraint);
172 
173  const auto p3_omega_max_constraint =
174  std::make_shared<SingleDimensionConstraint>(
175  P3::kOmegaIdx, kOmegaMax, true, "Omega Constraint (Max)");
176  const auto p3_omega_min_constraint =
177  std::make_shared<SingleDimensionConstraint>(
178  P3::kOmegaIdx, -kOmegaMax, false, "Omega Constraint (Min)");
179  const auto p3_a_max_constraint = std::make_shared<SingleDimensionConstraint>(
180  P3::kAIdx, kAMax, true, "Acceleration Constraint (Max)");
181  const auto p3_a_min_constraint = std::make_shared<SingleDimensionConstraint>(
182  P3::kAIdx, -kAMax, false, "Acceleration Constraint (Min)");
183  p3_cost.AddControlConstraint(2, p3_omega_max_constraint);
184  p3_cost.AddControlConstraint(2, p3_omega_min_constraint);
185  p3_cost.AddControlConstraint(2, p3_a_max_constraint);
186  p3_cost.AddControlConstraint(2, p3_a_min_constraint);
187 
188  // Penalize proximity.
189  const std::shared_ptr<SignedDistanceCost> p1_p2_collision_avoidance_cost(
190  new SignedDistanceCost({kP1XIdx, kP1YIdx}, {kP2XIdx, kP2YIdx},
191  FLAGS_buffer));
192  const std::shared_ptr<SignedDistanceCost> p1_p3_collision_avoidance_cost(
193  new SignedDistanceCost({kP1XIdx, kP1YIdx}, {kP3XIdx, kP3YIdx},
194  FLAGS_buffer));
195  const std::shared_ptr<SignedDistanceCost> p2_p3_collision_avoidance_cost(
196  new SignedDistanceCost({kP2XIdx, kP2YIdx}, {kP3XIdx, kP3YIdx},
197  FLAGS_buffer));
198 
199  constexpr bool kTakeMin = false;
200  const std::shared_ptr<ExtremeValueCost> p1_proximity_cost(
201  new ExtremeValueCost(
202  {p1_p2_collision_avoidance_cost, p1_p3_collision_avoidance_cost},
203  kTakeMin, "Proximity"));
204  const std::shared_ptr<ExtremeValueCost> p2_proximity_cost(
205  new ExtremeValueCost(
206  {p1_p2_collision_avoidance_cost, p2_p3_collision_avoidance_cost},
207  kTakeMin, "Proximity"));
208  const std::shared_ptr<ExtremeValueCost> p3_proximity_cost(
209  new ExtremeValueCost(
210  {p2_p3_collision_avoidance_cost, p1_p3_collision_avoidance_cost},
211  kTakeMin, "Proximity"));
212  p1_cost.AddStateCost(p1_proximity_cost);
213  p2_cost.AddStateCost(p2_proximity_cost);
214  p3_cost.AddStateCost(p3_proximity_cost);
215 
216  // Make sure costs are max-over-time.
217  p1_cost.SetMaxOverTime();
218  p2_cost.SetMaxOverTime();
219  p3_cost.SetMaxOverTime();
220 }
221 
222 inline std::vector<float> ThreePlayerCollisionAvoidanceReachabilityExample::Xs(
223  const VectorXf& x) const {
224  return {x(kP1XIdx), x(kP2XIdx), x(kP3XIdx)};
225 }
226 
227 inline std::vector<float> ThreePlayerCollisionAvoidanceReachabilityExample::Ys(
228  const VectorXf& x) const {
229  return {x(kP1YIdx), x(kP2YIdx), x(kP3YIdx)};
230 }
231 
232 inline std::vector<float>
233 ThreePlayerCollisionAvoidanceReachabilityExample::Thetas(
234  const VectorXf& x) const {
235  return {x(kP1HeadingIdx), x(kP2HeadingIdx), x(kP3HeadingIdx)};
236 }
237 
238 } // namespace ilqgames