ilqgames
A new real-time solver for large-scale differential games.
single_player_flat_car_6d.h
1 /*
2  * Copyright (c) 2019, 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 // Single player dynamics modeling a car. 5 states and 2 control inputs.
40 // State is [x, y, theta, phi, v, a], control is [omega, j], and dynamics are:
41 // \dot px = v cos theta
42 // \dot py = v sin theta
43 // \dot theta = (v / L) * tan phi
44 // \dot phi = omega
45 // \dot v = a
46 // \dot a = j
47 // Please refer to
48 // https://www.sciencedirect.com/science/article/pii/S2405896316301215
49 // for further details.
50 //
51 ///////////////////////////////////////////////////////////////////////////////
52 
53 #ifndef ILQGAMES_DYNAMICS_SINGLE_PLAYER_FLAT_CAR_6D_H
54 #define ILQGAMES_DYNAMICS_SINGLE_PLAYER_FLAT_CAR_6D_H
55 
56 #include <ilqgames/dynamics/single_player_flat_system.h>
57 #include <ilqgames/utils/types.h>
58 
59 #include <glog/logging.h>
60 
61 namespace ilqgames {
62 
64  public:
66  SinglePlayerFlatCar6D(float inter_axle_distance)
67  : SinglePlayerFlatSystem(kNumXDims, kNumUDims),
68  inter_axle_distance_(inter_axle_distance) {}
69 
70  // Compute time derivative of state.
71  VectorXf Evaluate(const VectorXf& x, const VectorXf& u) const;
72 
73  // Discrete time approximation of the underlying linearized system.
74  void LinearizedSystem(Eigen::Ref<MatrixXf> A, Eigen::Ref<MatrixXf> B) const;
75 
76  // Utilities for feedback linearization.
77  MatrixXf InverseDecouplingMatrix(const VectorXf& x) const;
78  VectorXf AffineTerm(const VectorXf& x) const;
79  VectorXf ToLinearSystemState(const VectorXf& x) const;
80  VectorXf FromLinearSystemState(const VectorXf& xi) const;
81  void Partial(const VectorXf& xi, std::vector<VectorXf>* grads,
82  std::vector<MatrixXf>* hesses) const;
83  bool IsLinearSystemStateSingular(const VectorXf& xi) const;
84 
85  // Distance metric between two states.
86  float DistanceBetween(const VectorXf& x0, const VectorXf& x1) const;
87 
88  // Position dimensions.
89  std::vector<Dimension> PositionDimensions() const { return {kPxIdx, kPyIdx}; }
90 
91  // Constexprs for state indices.
92  static const Dimension kNumXDims;
93  static const Dimension kPxIdx;
94  static const Dimension kPyIdx;
95  static const Dimension kThetaIdx;
96  static const Dimension kPhiIdx;
97  static const Dimension kVIdx;
98  static const Dimension kAIdx;
99  static const Dimension kVxIdx;
100  static const Dimension kVyIdx;
101  static const Dimension kAxIdx;
102  static const Dimension kAyIdx;
103 
104  // Constexprs for control indices.
105  static const Dimension kNumUDims;
106  static const Dimension kOmegaIdx;
107  static const Dimension kJerkIdx;
108 
109  private:
110  // Inter-axle distance. Determines turning radius.
111  const float inter_axle_distance_;
112 }; //\class SinglePlayerCar6D
113 
114 // ----------------------------- IMPLEMENTATION ----------------------------- //
115 
116 inline VectorXf SinglePlayerFlatCar6D::Evaluate(const VectorXf& x,
117  const VectorXf& u) const {
118  VectorXf xdot(xdim_);
119  xdot(kPxIdx) = x(kVIdx) * std::cos(x(kThetaIdx));
120  xdot(kPyIdx) = x(kVIdx) * std::sin(x(kThetaIdx));
121  xdot(kThetaIdx) = (x(kVIdx) / inter_axle_distance_) * std::tan(x(kPhiIdx));
122  xdot(kPhiIdx) = u(kOmegaIdx);
123  xdot(kVIdx) = x(kAIdx);
124  xdot(kAIdx) = u(kJerkIdx);
125 
126  return xdot;
127 }
128 
129 inline void SinglePlayerFlatCar6D::LinearizedSystem(
130  Eigen::Ref<MatrixXf> A, Eigen::Ref<MatrixXf> B) const {
131  A(kPxIdx, kVxIdx) += time::kTimeStep;
132  A(kPyIdx, kVyIdx) += time::kTimeStep;
133  A(kVxIdx, kAxIdx) += time::kTimeStep;
134  A(kVyIdx, kAyIdx) += time::kTimeStep;
135 
136  B(kAxIdx, 0) = time::kTimeStep;
137  B(kAyIdx, 1) = time::kTimeStep;
138 }
139 
140 inline MatrixXf SinglePlayerFlatCar6D::InverseDecouplingMatrix(
141  const VectorXf& x) const {
142  MatrixXf M_inv(kNumUDims, kNumUDims);
143 
144  const float sin_t = std::sin(x(kThetaIdx));
145  const float cos_t = std::cos(x(kThetaIdx));
146  // HACK! KSmallOffset should realy be 0...
147  const float kSmallOffset = sgn(x(kVIdx) + 0.0000001) * 0.00011;
148  const float cos_phi_v = std::cos(x(kPhiIdx)) / (x(kVIdx) + kSmallOffset);
149  const float scaling = inter_axle_distance_ * cos_phi_v * cos_phi_v;
150 
151  CHECK_GT(std::abs(x(kVIdx) + kSmallOffset), 1e-4);
152 
153  M_inv(0, 0) = -scaling * sin_t;
154  M_inv(0, 1) = scaling * cos_t;
155  M_inv(1, 0) = cos_t;
156  M_inv(1, 1) = sin_t;
157 
158  return M_inv;
159 }
160 
161 inline VectorXf SinglePlayerFlatCar6D::AffineTerm(const VectorXf& x) const {
162  VectorXf m = VectorXf::Zero(kNumUDims);
163 
164  const float sin_t = std::sin(x(kThetaIdx));
165  const float cos_t = std::cos(x(kThetaIdx));
166  const float tan_phi = std::tan(x(kPhiIdx));
167  const float v_over_l = x(kVIdx) / inter_axle_distance_;
168 
169  m(0) = -v_over_l * tan_phi *
170  (3.0 * x(kAIdx) * sin_t + v_over_l * x(kVIdx) * tan_phi * cos_t);
171  m(1) = v_over_l * tan_phi *
172  (3.0 * x(kAIdx) * cos_t - v_over_l * x(kVIdx) * tan_phi * sin_t);
173 
174  return m;
175 }
176 
177 inline VectorXf SinglePlayerFlatCar6D::ToLinearSystemState(
178  const VectorXf& x) const {
179  VectorXf xi(kNumXDims);
180 
181  const float sin_t = std::sin(x(kThetaIdx));
182  const float cos_t = std::cos(x(kThetaIdx));
183  const float tan_phi = std::tan(x(kPhiIdx));
184  const float vv_over_l = x(kVIdx) * x(kVIdx) / inter_axle_distance_;
185 
186  xi(kPxIdx) = x(kPxIdx);
187  xi(kPyIdx) = x(kPyIdx);
188  xi(kVxIdx) = x(kVIdx) * cos_t;
189  xi(kVyIdx) = x(kVIdx) * sin_t;
190  xi(kAxIdx) = x(kAIdx) * cos_t - vv_over_l * sin_t * tan_phi;
191  xi(kAyIdx) = x(kAIdx) * sin_t + vv_over_l * cos_t * tan_phi;
192 
193  return xi;
194 }
195 
196 inline VectorXf SinglePlayerFlatCar6D::FromLinearSystemState(
197  const VectorXf& xi) const {
198  VectorXf x(kNumXDims);
199 
200  x(kPxIdx) = xi(kPxIdx);
201  x(kPyIdx) = xi(kPyIdx);
202  x(kThetaIdx) = std::atan2(xi(kVyIdx), xi(kVxIdx));
203  x(kVIdx) = std::hypot(xi(kVyIdx), xi(kVxIdx));
204 
205  const float cos_t = xi(kVxIdx) / x(kVIdx);
206  const float sin_t = xi(kVyIdx) / x(kVIdx);
207 
208  x(kAIdx) = cos_t * xi(kAxIdx) + sin_t * xi(kAyIdx);
209  x(kPhiIdx) = std::atan((x(kAIdx) * cos_t - xi(kAxIdx)) *
210  inter_axle_distance_ / (x(kVIdx) * x(kVIdx) * sin_t));
211 
212  return x;
213 }
214 
215 inline bool SinglePlayerFlatCar6D::IsLinearSystemStateSingular(
216  const VectorXf& xi) const {
217  constexpr float kTolerance = 1e-2;
218  return (std::isnan(xi(kVxIdx)) || std::isnan(xi(kVyIdx))) ||
219  (std::abs(xi(kVxIdx)) < kTolerance &&
220  std::abs(xi(kVyIdx)) < kTolerance);
221 }
222 
223 inline float SinglePlayerFlatCar6D::DistanceBetween(const VectorXf& x0,
224  const VectorXf& x1) const {
225  // Squared distance in position space.
226  const float dx = x0(kPxIdx) - x1(kPxIdx);
227  const float dy = x0(kPyIdx) - x1(kPyIdx);
228  return dx * dx + dy * dy;
229 }
230 
231 } // namespace ilqgames
232 
233 #endif