DirectTrajOpt.jl
DirectTrajOpt.jl provides a framework for setting up and solving direct trajectory optimization problems using nonlinear programming.
Problem Formulation
DirectTrajOpt solves problems of the form:
\[\begin{align*} \underset{x_{1:N}, u_{1:N}}{\text{minimize}} \quad & J(x_{1:N}, u_{1:N}) \\ \text{subject to} \quad & f(x_{k+1}, x_k, u_k, \Delta t, t_k) = 0, \quad k = 1, \ldots, N-1\\ & c_k(x_k, u_k) \geq 0, \quad k = 1, \ldots, N \\ & x_1 = x_{\text{init}}, \quad x_N = x_{\text{goal}} \\ \end{align*}\]
where:
J(x, u)is the objective function to minimizef(·)represents system dynamics encoded via integratorsc(·)represents additional nonlinear constraintsxis the state trajectoryuis the control trajectory
The underlying nonlinear solver is Ipopt.jl.
Installation
using Pkg
Pkg.add("DirectTrajOpt")Quick Example
using DirectTrajOpt
using NamedTrajectories
# Define trajectory
traj = NamedTrajectory(
(x = randn(2, 50), u = randn(1, 50), Δt = fill(0.1, 50));
timestep=:Δt,
controls=:u,
initial=(x = [0.0, 0.0],),
final=(x = [1.0, 0.0],)
)
# Define dynamics
A = [-0.1 1.0; -1.0 -0.1]
B = reshape([0.0, 1.0], 2, 1)
integrator = BilinearIntegrator([A B], traj, :x, :u)
# Define objective
obj = QuadraticRegularizer(:u, traj, 1.0)
# Create and solve problem
prob = DirectTrajOptProblem(traj, obj, integrator)
solve!(prob; max_iter=100)Key Features
- Flexible dynamics: Define system evolution via integrators
- Modular objectives: Combine multiple cost terms (regularization, minimum time, etc.)
- Constraint support: Bounds, equality, and general nonlinear constraints
- Automatic differentiation: Efficient gradients and Hessians
- Sparse formulations: Exploits problem structure for efficiency
Building Documentation
This package uses a Documenter config that is shared with many of our other repositories. To build the docs, you will need to run the docs setup script to clone and pull down the utility.
# first time only
./docs/get_docs_utils.sh # or ./get_docs_utils.sh if cwd is in ./docs/To build the docs pages:
julia --project=docs docs/make.jlor editing the docs live:
julia --project=docs
> using LiveServer, Piccolo, Revise
> servedocs(literate_dir="docs/literate", skip_dirs=["docs/src/generated", "docs/src/assets/"], skip_files=["docs/src/index.md"])Note:
servedocsneeds to watch a subset of the files in thedocs/folder. If it watches files that are generated on a docs build/re-build,servedocswill continuously try to re-serve the pages.To prevent this, ensure all generated files are included in the skip dirs or skip files args for
servedocs.
For example, if we forget index.md like so:
julia --project=docs
> using LiveServer, Piccolo, Revise
> servedocs(literate_dir="docs/literate", skip_dirs=["docs/src/generated", "docs/src/assets/"])it will not build and serve.
"It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to take away." - Antoine de Saint-Exupéry