Skip to content

lassepe/iLQGames.jl

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 
 
 

iLQGames.jl

CI codecov License

iLQGames.jl is a framework for rapidly designing and solving nonlinear general-sum differential games, built around iterative linear-quadratic game approximations.

A brief introduction to this framework and benchmarks against a C++ implementation can be found in this short workshop manuscript. Finally, this paper demonstrates the flexibility and performance of iLQGames.jl by combining it with a particle-filter scheme to reason about uncertainty in differential games in real-time.

Watch the video

Installation

Within the Julia REPL run:

using Pkg
Pkg.add(PackageSpec(url="https://github.com/lassepe/iLQGames.jl"))

Example

Here is an example of two players controlling a single 4D-unicycle. Player-1 controls the steering, Player-2 controls the acceleration.

1. Describe Dynamics

We define a Unicycle as a subtype of our ControlSystem type and implement the differential equation by overloading dx for our type.

using iLQGames
import iLQGames: dx

# parameters: number of states, number of inputs, sampling time, horizon
nx, nu, ΔT, game_horizon = 4, 2, 0.1, 200

# setup the dynamics
struct Unicycle <: ControlSystem{ΔT,nx,nu} end
# the differential equation of a uncycle with state: (px, py, phi, v)
dx(cs::Unicycle, x, u, t) = SVector(x[4]cos(x[3]), x[4]sin(x[3]), u[1], u[2])
dynamics = Unicycle()

2. Setup Costs

To setup the costs encoding each players objectives, we can derive a custom subtype from PlayerCost, or, as done here, simply hand the cost function as a lambda function to the FunctionPlayerCost.

# player-1 wants the unicycle to stay close to the origin,
# player-2 wants to keep close to 1 m/s
costs = (FunctionPlayerCost((g, x, u, t) -> (x[1]^2 + x[2]^2 + u[1]^2)),
         FunctionPlayerCost((g, x, u, t) -> ((x[4] - 1)^2 + u[2]^2)))
# indices of inputs that each player controls
player_inputs = (SVector(1), SVector(2))

3. Solve the Game

With this information we can construct the game...

g = GeneralGame(game_horizon, player_inputs, dynamics, costs)

...and solve it for some initial conditions x0. Automatic differentiation will save us from having to specify how to compute LQ approximations of the system.

# get a solver, choose initial conditions and solve (in about 9 ms with automatic differentiation)
solver = iLQSolver(g)
x0 = SVector(1, 1, 0, 0.5)
converged, trajectory, strategies = solve(g, solver, x0)

Finally, we can visualize the path of the unicycle as follows (x- and y-position):

# for visualization we need to state which state indices correspond to px and py
position_indices = tuple(SVector(1,2))
# Note: you can use the `plot_traj` call without @animated to get a non-animated plot instead.
@animated(plot_traj(trajectory, g, [:red, :green], player_inputs),
          1:game_horizon, "minimal_example.gif")

At the equilibrium solution, Player-2 accelerates to reach the desired speed. Player-1 steers the unicycle in a figure-8 to stay close to the origin.:

About

Rapidly designing and solving differential games in Julia.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages