aligator  0.10.0
A primal-dual augmented Lagrangian-type solver for nonlinear trajectory optimization.
Loading...
Searching...
No Matches
Trajectory optimization problems

Trajectory optimization

The objective of this library is to model and solve optimal control problems (OCPs) of the form

\begin{align} \min_{x,u}~& \int_0^T \ell(x, u)\, dt + \ell_\mathrm{f}(x(T)) \\ \subjectto & \dot x (t) = f(x(t), u(t)) \\ & g(x(t), u(t)) = 0 \\ & h(x(t), u(t)) \leq 0 \end{align}

Transcription

A transcription translates the continuous-time OCP to a discrete-time, finite-dimensional nonlinear program. Aligator allows us to consider transcriptions with implicit discrete dynamics: \begin{aligned} \min_{\bmx,\bmu}~& J(\bmx, \bmu) = \sum_{i=0}^{N-1} \ell_i(x_i, u_i) + \ell_N(x_N) \\ \subjectto & f(x_i, u_i, x_{i+1}) = 0 \\ & g(x_i, u_i) = 0 \\ & h(x_i, u_i) \leq 0 \end{aligned}

In aligator, trajectory optimization problems are described using the class TrajOptProblemTpl. Each TrajOptProblemTpl is described by a succession of stages (StageModelTpl) which encompass the set of constraints and the cost function (class CostAbstractTpl) for this stage.

Additionally, a TrajOptProblemTpl must provide an initial condition \( x_0 = \bar{x} \), a terminal cost $$ \ell_{\mathrm{f}}(x_N) $$ on the terminal state \(x_N \); optionally, a terminal constraint \(g(x_N) = 0, h(x_N) \leq 0 \) on this state may be added.

Stage models

A stage model (StageModelTpl) describes a node in the discrete-time optimal control problem: it consists in a running cost function, and a vector of constraints (StageConstraintTpl), the first of which must describe system dynamics (through a DynamicsModelTpl).

Example

Define and solve an LQR (Python API):

1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# SPDX-License-Identifier: BSD-2-Clause
5# Copyright 2023 Inria
6
7"""Formulating and solving a linear quadratic regulator with Aligator."""
8
9import matplotlib.pyplot as plt
10import numpy as np
11import tap
12
13import aligator
14from aligator import constraints, dynamics, manifolds
15from aligator.utils.plotting import plot_convergence
16
17
18class Args(tap.Tap):
19 term_cstr: bool = False
20 bounds: bool = False
21
22
23args = Args().parse_args()
24np.random.seed(42)
25
26TAG = "LQR"
27if args.bounds:
28 TAG += "_bounded"
29if args.term_cstr:
30 TAG += "_cstr"
31
32nx = 3 # dimension of the state manifold
33nu = 3 # dimension of the input
34space = manifolds.VectorSpace(nx)
35x0 = space.neutral() + (0.2, 0.3, -0.1)
36
37# Linear discrete dynamics: x[t+1] = A x[t] + B u[t] + c
38A = np.eye(nx)
39A[0, 1] = -0.2
40A[1, 0] = 0.2
41B = np.eye(nx)[:, :nu]
42B[2, :] = 0.4
43c = np.zeros(nx)
44c[:] = (0.0, 0.0, 0.1)
45
46# Quadratic cost: ½ x^T Q x + ½ u^T R u + x^T N u
47Q = 1e-2 * np.eye(nx)
48R = 1e-2 * np.eye(nu)
49N = 1e-5 * np.eye(nx, nu)
50
51Qf = np.eye(nx)
52if args.term_cstr: # <-- TODO: should it be `not term_cstr`?
53 Qf[:, :] = 0.0
54
55
56# These matrices define the costs and constraints that apply at each stage
57# (a.k.a. node) of our trajectory optimization problem
58rcost0 = aligator.QuadraticCost(Q, R, N)
59term_cost = aligator.QuadraticCost(Qf, R)
60dynmodel = dynamics.LinearDiscreteDynamics(A, B, c)
61stage = aligator.StageModel(rcost0, dynmodel)
62if args.bounds:
63 u_min = -0.18 * np.ones(nu)
64 u_max = +0.18 * np.ones(nu)
65 ctrl_fn = aligator.ControlErrorResidual(nx, np.zeros(nu))
66 stage.addConstraint(ctrl_fn, constraints.BoxConstraint(u_min, u_max))
67
68
69# Build our problem by appending stages and the optional terminal constraint
70nsteps = 20
71problem = aligator.TrajOptProblem(x0, nu, space, term_cost)
72
73for i in range(nsteps):
74 problem.addStage(stage)
75
76xtar2 = 0.1 * np.ones(nx)
77if args.term_cstr:
78 term_fun = aligator.StateErrorResidual(space, nu, xtar2)
79 problem.addTerminalConstraint(term_fun, constraints.EqualityConstraintSet())
80
81# Instantiate a solver separately
82mu_init = 1e-1 if args.bounds else 1e-4
83verbose = aligator.VerboseLevel.VERBOSE
84tol = 1e-8
85solver = aligator.SolverProxDDP(tol, mu_init, verbose=verbose)
86
87his_cb = aligator.HistoryCallback(solver)
88solver.registerCallback("his", his_cb)
89print("Registered callbacks:", solver.getCallbackNames().tolist())
90solver.max_iters = 20
91solver.rollout_type = aligator.ROLLOUT_LINEAR
92
93u0 = np.zeros(nu)
94us_i = [u0] * nsteps
95xs_i = aligator.rollout(dynmodel, x0, us_i)
96prob_data = aligator.TrajOptData(problem)
97problem.evaluate(xs_i, us_i, prob_data)
98
99solver.setup(problem)
100solver.run(problem, xs_i, us_i)
101res = solver.results
102ws = solver.workspace
103print(res)
104
105plt.subplot(121)
106fig1: plt.Figure = plt.gcf()
107fig1.set_figwidth(6.4)
108fig1.set_figheight(3.6)
109
110lstyle = {"lw": 0.9, "marker": ".", "markersize": 5}
111trange = np.arange(nsteps + 1)
112plt.plot(res.xs, ls="-", **lstyle)
113
114if args.term_cstr:
115 plt.hlines(
116 xtar2,
117 *trange[[0, -1]],
118 ls="-",
119 lw=1.0,
120 colors="k",
121 alpha=0.4,
122 label=r"$x_\mathrm{tar}$",
123 )
124plt.hlines(
125 0.0,
126 *trange[[0, -1]],
127 ls=":",
128 lw=0.6,
129 colors="k",
130 alpha=0.4,
131 label=r"$x=0$",
132)
133plt.title("State trajectory $x(t)$")
134plt.xlabel("Time $i$")
135plt.legend(frameon=False)
136
137plt.subplot(122)
138plt.plot(res.us, **lstyle)
139if args.bounds:
140 plt.hlines(
141 np.concatenate([u_min, u_max]),
142 *trange[[0, -1]],
143 ls="-",
144 colors="tab:red",
145 lw=1.8,
146 alpha=0.4,
147 label=r"$\bar{u}$",
148 )
149plt.xlabel("Time $i$")
150plt.title("Controls $u(t)$")
151plt.legend(frameon=False, loc="lower right")
152plt.tight_layout()
153
154
155fig2: plt.Figure = plt.figure(figsize=(6.4, 3.6))
156ax: plt.Axes = fig2.add_subplot()
157niter = res.num_iters
158ax.hlines(
159 tol,
160 0,
161 niter,
162 colors="k",
163 linestyles="-",
164 linewidth=2.0,
165)
166plot_convergence(his_cb, ax, res, show_al_iters=True)
167ax.set_title("Convergence (constrained LQR)")
168fig2.tight_layout()
169fig_dicts = {"traj": fig1, "conv": fig2}
170
171for name, _fig in fig_dicts.items():
172 _fig: plt.Figure
173 _fig.savefig(f"assets/{TAG}_{name}.pdf")
174
175plt.show()
math_types< Scalar >::VectorOfVectors rollout(const std::vector< xyz::polymorphic< DynamicsModelTpl< Scalar > > > &dyn_models, const typename math_types< Scalar >::VectorXs &x0, const typename math_types< Scalar >::VectorOfVectors &us, typename math_types< Scalar >::VectorOfVectors &xout)
Perform a rollout of the supplied dynamical models.
Definition rollout.hpp:9