aligator  0.16.0
A versatile and efficient C++ library for real-time constrained 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
68print(stage)
69
70# Build our problem by appending stages and the optional terminal constraint
71nsteps = 20
72problem = aligator.TrajOptProblem(x0, nu, space, term_cost)
73
74for i in range(nsteps):
75 problem.addStage(stage)
76
77xtar2 = 0.1 * np.ones(nx)
78if args.term_cstr:
79 term_fun = aligator.StateErrorResidual(space, nu, xtar2)
80 problem.addTerminalConstraint(term_fun, constraints.EqualityConstraintSet())
81
82# Instantiate a solver separately
83mu_init = 2e-3 if args.bounds else 1e-7
84verbose = aligator.VerboseLevel.VERBOSE
85tol = 1e-8
86solver = aligator.SolverProxDDP(tol, mu_init, verbose=verbose)
87
88his_cb = aligator.HistoryCallback(solver)
89solver.registerCallback("his", his_cb)
90print("Registered callbacks:", solver.getCallbackNames().tolist())
91solver.max_iters = 20
92solver.rollout_type = aligator.ROLLOUT_LINEAR
93
94u0 = np.zeros(nu)
95us_i = [u0] * nsteps
96xs_i = aligator.rollout(dynmodel, x0, us_i)
97prob_data = aligator.TrajOptData(problem)
98problem.evaluate(xs_i, us_i, prob_data)
99
100solver.setup(problem)
101solver.run(problem, xs_i, us_i)
102res: aligator.Results = solver.results
103ws: aligator.Workspace = solver.workspace
104print(res)
105print(ws.state_dual_infeas.tolist())
106print(ws.control_dual_infeas.tolist())
107
108plt.subplot(121)
109fig1: plt.Figure = plt.gcf()
110fig1.set_figwidth(6.4)
111fig1.set_figheight(3.6)
112
113lstyle = {"lw": 0.9, "marker": ".", "markersize": 5}
114trange = np.arange(nsteps + 1)
115plt.plot(res.xs, ls="-", **lstyle)
116
117if args.term_cstr:
118 plt.hlines(
119 xtar2,
120 *trange[[0, -1]],
121 ls="-",
122 lw=1.0,
123 colors="k",
124 alpha=0.4,
125 label=r"$x_\mathrm{tar}$",
126 )
127plt.hlines(
128 0.0,
129 *trange[[0, -1]],
130 ls=":",
131 lw=0.6,
132 colors="k",
133 alpha=0.4,
134 label=r"$x=0$",
135)
136plt.title("State trajectory $x(t)$")
137plt.xlabel("Time $i$")
138plt.legend(frameon=False)
139
140plt.subplot(122)
141plt.plot(res.us, **lstyle)
142if args.bounds:
143 plt.hlines(
144 np.concatenate([u_min, u_max]),
145 *trange[[0, -1]],
146 ls="-",
147 colors="tab:red",
148 lw=1.8,
149 alpha=0.4,
150 label=r"$\bar{u}$",
151 )
152plt.xlabel("Time $i$")
153plt.title("Controls $u(t)$")
154plt.legend(frameon=False, loc="lower right")
155plt.tight_layout()
156
157
158fig2: plt.Figure = plt.figure(figsize=(6.4, 3.6))
159ax: plt.Axes = fig2.add_subplot()
160niter = res.num_iters
161ax.hlines(
162 tol,
163 0,
164 niter,
165 colors="k",
166 linestyles="-",
167 linewidth=2.0,
168)
169plot_convergence(his_cb, ax, res, show_al_iters=True)
170ax.set_title("Convergence (constrained LQR)")
171fig2.tight_layout()
172fig_dicts = {"traj": fig1, "conv": fig2}
173
174for name, _fig in fig_dicts.items():
175 _fig: plt.Figure
176 _fig.savefig(f"assets/{TAG}_{name}.pdf")
177
178plt.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:11