ilqgames
A new real-time solver for large-scale differential games.
air_3d.h
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 // Air3D dynamics, from:
40 // https://www.cs.ubc.ca/~mitchell/Papers/publishedIEEEtac05.pdf.
41 //
42 // Here, two Dubins cars are navigating in relative coordinates, and the usual
43 // setup is a pursuit-evasion game.
44 //
45 // Dynamics are:
46 // \dot r_x = -v_e + v_p cos(r_theta) + u_e r_y
47 // \dot r_y = v_p sin(r_theta) - u_e r_x
48 // \dot r_theta = u_p - u_e
49 // and the convention below is that controls are "omega" and the evader is P1
50 // and the pursuer is P2.
51 //
52 //
53 ///////////////////////////////////////////////////////////////////////////////
54 
55 #ifndef ILQGAMES_DYNAMICS_AIR_3D_H
56 #define ILQGAMES_DYNAMICS_AIR_3D_H
57 
58 #include <ilqgames/dynamics/multi_player_dynamical_system.h>
59 #include <ilqgames/utils/types.h>
60 
61 #include <glog/logging.h>
62 
63 namespace ilqgames {
64 
66  public:
67  ~Air3D() {}
68  Air3D(float evader_speed, float pursuer_speed)
69  : evader_speed_(evader_speed),
70  pursuer_speed_(pursuer_speed),
71  MultiPlayerDynamicalSystem(kNumXDims) {}
72 
73  // Compute time derivative of state.
74  VectorXf Evaluate(Time t, const VectorXf& x,
75  const std::vector<VectorXf>& us) const;
76 
77  // Compute a discrete-time Jacobian linearization.
78  LinearDynamicsApproximation Linearize(Time t, const VectorXf& x,
79  const std::vector<VectorXf>& us) const;
80 
81  // Distance metric between two states.
82  float DistanceBetween(const VectorXf& x0, const VectorXf& x1) const;
83 
84  // Getters.
85  Dimension UDim(PlayerIndex player_idx) const {
86  DCHECK(player_idx == 0 || player_idx == 1);
87  return (player_idx == 0) ? kNumU1Dims : kNumU2Dims;
88  }
89  PlayerIndex NumPlayers() const { return kNumPlayers; }
90  std::vector<Dimension> PositionDimensions() const { return {kRxIdx, kRyIdx}; }
91 
92  // Speed of each player.
93  const float evader_speed_;
94  const float pursuer_speed_;
95 
96  // Constexprs for state indices.
97  static const Dimension kNumXDims;
98  static const Dimension kRxIdx;
99  static const Dimension kRyIdx;
100  static const Dimension kRThetaIdx;
101 
102  // Constexprs for control indices.
103  static const PlayerIndex kNumPlayers;
104 
105  static const Dimension kNumU1Dims;
106  static const Dimension kOmega1Idx;
107 
108  static const Dimension kNumU2Dims;
109  static const Dimension kOmega2Idx;
110 }; //\class TwoPlayerUnicycle4D
111 
112 // ----------------------------- IMPLEMENTATION ----------------------------- //
113 
114 inline VectorXf Air3D::Evaluate(Time t, const VectorXf& x,
115  const std::vector<VectorXf>& us) const {
116  CHECK_EQ(us.size(), NumPlayers());
117 
118  // Populate xdot one dimension at a time.
119  VectorXf xdot(xdim_);
120  xdot(kRxIdx) = -evader_speed_ + pursuer_speed_ * std::cos(x(kRThetaIdx)) +
121  us[0](kOmega1Idx) * x(kRyIdx);
122  xdot(kRyIdx) =
123  pursuer_speed_ * std::sin(x(kRThetaIdx)) - us[0](kOmega1Idx) * x(kRxIdx);
124  xdot(kRThetaIdx) = us[1](kOmega2Idx) - us[0](kOmega1Idx);
125 
126  return xdot;
127 }
128 
129 inline LinearDynamicsApproximation Air3D::Linearize(
130  Time t, const VectorXf& x, const std::vector<VectorXf>& us) const {
131  LinearDynamicsApproximation linearization(*this);
132 
133  const float ctheta = std::cos(x(kRThetaIdx)) * time::kTimeStep;
134  const float stheta = std::sin(x(kRThetaIdx)) * time::kTimeStep;
135 
136  linearization.A(kRxIdx, kRyIdx) += us[0](kOmega1Idx) * time::kTimeStep;
137  linearization.A(kRxIdx, kRThetaIdx) -= pursuer_speed_ * stheta;
138 
139  linearization.A(kRyIdx, kRxIdx) -= us[0](kOmega1Idx) * time::kTimeStep;
140  linearization.A(kRyIdx, kRThetaIdx) += pursuer_speed_ * ctheta;
141 
142  linearization.Bs[0](kRxIdx, kOmega1Idx) = x(kRyIdx) * time::kTimeStep;
143  linearization.Bs[0](kRyIdx, kOmega1Idx) = -x(kRxIdx) * time::kTimeStep;
144  linearization.Bs[0](kRThetaIdx, kOmega1Idx) = -time::kTimeStep;
145 
146  linearization.Bs[1](kRThetaIdx, kOmega2Idx) = time::kTimeStep;
147 
148  return linearization;
149 }
150 
151 inline float Air3D::DistanceBetween(const VectorXf& x0,
152  const VectorXf& x1) const {
153  // Squared distance in position space.
154  // NOTE: doesn't really make sense in this context, so logging an error.
155  LOG(ERROR) << "Trying to compute distance between to relative states.";
156  return (x0.head(2) - x1.head(2)).squaredNorm();
157 }
158 
159 } // namespace ilqgames
160 
161 #endif