ilqgames
A new real-time solver for large-scale differential games.
two_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 // Two player collision-avoidance example using approximate HJ reachability.
40 //
41 ///////////////////////////////////////////////////////////////////////////////
42 
43 #include <ilqgames/cost/quadratic_cost.h>
44 #include <ilqgames/cost/signed_distance_cost.h>
45 #include <ilqgames/dynamics/concatenated_dynamical_system.h>
46 #include <ilqgames/dynamics/single_player_car_5d.h>
47 #include <ilqgames/examples/two_player_collision_avoidance_reachability_example.h>
48 #include <ilqgames/geometry/draw_shapes.h>
49 #include <ilqgames/geometry/polyline2.h>
50 #include <ilqgames/solver/ilq_solver.h>
51 #include <ilqgames/solver/problem.h>
52 #include <ilqgames/solver/solver_params.h>
53 #include <ilqgames/utils/types.h>
54 
55 #include <math.h>
56 #include <memory>
57 #include <vector>
58 
59 // Initial state command-line flags.
60 DEFINE_double(px0, 0.0, "Initial x-position (m).");
61 DEFINE_double(py0, -5.0, "Initial y-position (m).");
62 
63 namespace ilqgames {
64 
65 namespace {
66 
67 // Control cost weight.
68 static constexpr float kOmegaCostWeight = 0.1;
69 
70 // Initial state.
71 static constexpr float kP1InitialHeading = 0.1; // rad
72 static constexpr float kP1InitialSpeed = 5.0; // m/s
73 static constexpr float kP2InitialX = 0.0; // m
74 static constexpr float kP2InitialY = 0.0; // m
75 static constexpr float kP2InitialHeading = 0.0; // rad
76 static constexpr float kP2InitialSpeed = 5.0; // m/s
77 
78 // State dimensions.
79 using P1 = SinglePlayerCar5D;
80 using P2 = 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 } // anonymous namespace
94 
95 void TwoPlayerCollisionAvoidanceReachabilityExample::ConstructDynamics() {
96  dynamics_.reset(new ConcatenatedDynamicalSystem(
97  {std::make_shared<P1>(kInterAxleDistance),
98  std::make_shared<P2>(kInterAxleDistance)}));
99 }
100 
101 void TwoPlayerCollisionAvoidanceReachabilityExample::ConstructInitialState() {
102  x0_ = VectorXf::Zero(dynamics_->XDim());
103  x0_(kP1XIdx) = FLAGS_px0;
104  x0_(kP1YIdx) = FLAGS_py0;
105  x0_(kP1HeadingIdx) = kP1InitialHeading;
106  x0_(kP1VIdx) = kP1InitialSpeed;
107  x0_(kP2XIdx) = kP2InitialX;
108  x0_(kP2YIdx) = kP2InitialY;
109  x0_(kP2HeadingIdx) = kP2InitialHeading;
110  x0_(kP2VIdx) = kP2InitialSpeed;
111 }
112 
113 void TwoPlayerCollisionAvoidanceReachabilityExample::ConstructPlayerCosts() {
114  // Set up costs for all players.
115  player_costs_.emplace_back("P1");
116  player_costs_.emplace_back("P2");
117  auto& p1_cost = player_costs_[0];
118  auto& p2_cost = player_costs_[1];
119 
120  const auto control_cost =
121  std::make_shared<QuadraticCost>(kOmegaCostWeight, -1, 0.0, "ControlCost");
122  p1_cost.AddControlCost(0, control_cost);
123  p2_cost.AddControlCost(1, control_cost);
124 
125  // Collision-avoidance cost.
126  auto p1_position = [](Time t) {
127  return Point2(FLAGS_px0, FLAGS_py0) +
128  t * kP1InitialSpeed *
129  Point2(std::cos(kP1InitialHeading), std::sin(kP1InitialHeading));
130  }; // p1_position
131  auto p2_position = [](Time t) {
132  return Point2(kP2InitialX, kP2InitialY) +
133  t * kP2InitialSpeed *
134  Point2(std::cos(kP2InitialHeading), std::sin(kP2InitialHeading));
135  }; // p2_position
136 
137  // NOTE: Assumes line segments traced by each player at initialization do not
138  // intersect.
139  const float nominal_distance = (p1_position(0.5 * time::kTimeHorizon) -
140  p2_position(0.5 * time::kTimeHorizon))
141  .norm();
142  const std::shared_ptr<SignedDistanceCost> collision_avoidance_cost(
143  new SignedDistanceCost({kP1XIdx, kP1YIdx}, {kP2XIdx, kP2YIdx},
144  nominal_distance, "CollisionAvoidance"));
145  p1_cost.AddStateCost(collision_avoidance_cost);
146  p2_cost.AddStateCost(collision_avoidance_cost);
147 
148  // Make sure costs are max-over-time.
149  p1_cost.SetMaxOverTime();
150  p2_cost.SetMaxOverTime();
151 }
152 
153 inline std::vector<float> TwoPlayerCollisionAvoidanceReachabilityExample::Xs(
154  const VectorXf& x) const {
155  return {x(kP1XIdx), x(kP2XIdx)};
156 }
157 
158 inline std::vector<float> TwoPlayerCollisionAvoidanceReachabilityExample::Ys(
159  const VectorXf& x) const {
160  return {x(kP1YIdx), x(kP2YIdx)};
161 }
162 
163 inline std::vector<float>
164 TwoPlayerCollisionAvoidanceReachabilityExample::Thetas(
165  const VectorXf& x) const {
166  return {x(kP1HeadingIdx), x(kP2HeadingIdx)};
167 }
168 
169 } // namespace ilqgames