smooth_feedback
Control and estimation on Lie groups
Loading...
Searching...
No Matches
asif_func.hpp
Go to the documentation of this file.
1// Copyright (C) 2022 Petter Nilsson. MIT License.
2
3#pragma once
4
10#include <Eigen/Core>
11#include <boost/numeric/odeint.hpp>
12#include <smooth/compat/odeint.hpp>
13#include <smooth/concepts/lie_group.hpp>
14#include <smooth/diff.hpp>
15
16#include <algorithm>
17#include <limits>
18#include <utility>
19
20#include "common.hpp"
21#include "qp.hpp"
22
23namespace smooth::feedback {
24
39template<LieGroup X, Manifold U>
40 requires(Dof<X> > 0 && Dof<U> > 0)
42{
44 double T{1};
46 X x0{Default<X>()};
48 U u_des{Default<U>()};
50 Eigen::Matrix<double, Dof<U>, 1> W_u{Eigen::Matrix<double, Dof<U>, 1>::Ones()};
53};
54
59{
61 std::size_t K{10};
63 double alpha{1};
65 double dt{0.1};
67 double relax_cost{100};
68};
69
78template<LieGroup X, Manifold U>
79 requires(Dof<X> > 0 && Dof<U> > 0)
80void asif_to_qp_allocate(QuadraticProgram<-1, -1, double> & qp, std::size_t K, std::size_t nu_ineq, std::size_t nh)
81{
82 static constexpr int nx = Dof<X>;
83 static constexpr int nu = Dof<U>;
84
85 static_assert(nx > 0, "State space dimension must be static");
86 static_assert(nu > 0, "Input space dimension must be static");
87
88 const int M = K * nh + nu_ineq + 1;
89 const int N = nu + 1;
90
91 qp.A.setZero(M, N);
92 qp.l.setZero(M);
93 qp.u.setZero(M);
94
95 qp.P.setZero(N, N);
96 qp.q.setZero(N);
97}
98
104template<LieGroup X, Manifold U, diff::Type DT = diff::Type::Default>
105 requires(Dof<X> > 0 && Dof<U> > 0)
108 const ASIFProblem<X, U> & pbm,
109 const ASIFtoQPParams & prm,
110 auto && f,
111 auto && h,
112 auto && bu)
113{
114 using boost::numeric::odeint::euler, boost::numeric::odeint::vector_space_algebra;
115 using std::placeholders::_1;
116
117 static constexpr int nx = Dof<X>;
118 static constexpr int nu = Dof<U>;
119 static constexpr int nh = std::invoke_result_t<decltype(h), double, X>::SizeAtCompileTime;
120
121 euler<X, double, Tangent<X>, double, vector_space_algebra> state_stepper{};
122 euler<TangentMap<X>, double, TangentMap<X>, double, vector_space_algebra> sensi_stepper{};
123
124 const int nu_ineq = pbm.ulim.A.rows();
125
126 [[maybe_unused]] const int M = prm.K * nh + nu_ineq + 1;
127 [[maybe_unused]] const int N = nu + 1;
128
129 assert(qp.A.rows() == M);
130 assert(qp.A.cols() == N);
131 assert(qp.l.rows() == M);
132 assert(qp.u.rows() == M);
133
134 assert(qp.P.rows() == N);
135 assert(qp.P.cols() == N);
136 assert(qp.q.rows() == N);
137
138 // iteration variables
139 const double tau = pbm.T / static_cast<double>(prm.K);
140 const double dt = std::min<double>(prm.dt, tau);
141 double t = 0;
142 X x = pbm.x0;
143 TangentMap<X> dx_dx0 = TangentMap<X>::Identity();
144
145 // define ODEs for closed-loop dynamics and its sensitivity
146 const auto x_ode = [&f, &bu](const X & xx, Tangent<X> & dd, double tt) { dd = f(xx, bu(tt, xx)); };
147
148 const auto dx_dx0_ode = [&f, &bu, &x](const auto & S_v, auto & dS_dt_v, double tt) {
149 auto f_cl = [&]<typename T>(const CastT<T, X> & vx) { return f(vx, bu(T(tt), vx)); };
150 const auto [fcl, dr_fcl_dx] = diff::dr<1, DT>(std::move(f_cl), wrt(x));
151 dS_dt_v = (-ad<X>(fcl) + dr_fcl_dx) * S_v;
152 };
153
154 // value of dynamics at call time
155 const auto [f0, d_f0_du] =
156 diff::dr<1, DT>([&]<typename T>(const CastT<T, U> & vu) { return f(cast<T>(x), vu); }, wrt(pbm.u_des));
157
158 // loop over constraint number
159 for (auto k = 0u; k != prm.K; ++k) {
160 // differentiate barrier function w.r.t. x
161 const auto [hval, dh_dtx] =
162 diff::dr<1, DT>([&h]<typename T>(const T & vt, const CastT<T, X> & vx) { return h(vt, vx); }, wrt(t, x));
163
164 const Eigen::Matrix<double, nh, 1> dh_dt = dh_dtx.template leftCols<1>();
165 const Eigen::Matrix<double, nh, nx> dh_dx = dh_dtx.template rightCols<nx>();
166
167 // insert barrier constraint
168 const Eigen::Matrix<double, nh, nx> dh_dx0 = dh_dx * dx_dx0;
169 qp.A.template block<nh, nu>(k * nh, 0) = dh_dx0 * d_f0_du;
170 qp.l.template segment<nh>(k * nh) = -dh_dt - prm.alpha * hval - dh_dx0 * f0;
171 qp.u.template segment<nh>(k * nh).setConstant(std::numeric_limits<double>::infinity());
172
173 // integrate system and sensitivity forward until next constraint
174 double dt_act = std::min(dt, tau * (k + 1) - t);
175 while (t < tau * (k + 1)) {
176 state_stepper.do_step(x_ode, x, t, dt_act);
177 sensi_stepper.do_step(dx_dx0_ode, dx_dx0, t, dt_act);
178 t += dt_act;
179 }
180 }
181
182 // relaxation of barrier constraints
183 qp.A.block(0, nu, prm.K * nh, 1).setConstant(1);
184
185 // input bounds
186 qp.A.block(prm.K * nh, 0, nu_ineq, nu) = pbm.ulim.A;
187 qp.l.segment(prm.K * nh, nu_ineq) = pbm.ulim.l - pbm.ulim.A * rminus(pbm.u_des, pbm.ulim.c);
188 qp.u.segment(prm.K * nh, nu_ineq) = pbm.ulim.u - pbm.ulim.A * rminus(pbm.u_des, pbm.ulim.c);
189
190 // upper and lower bounds on delta
191 qp.A(prm.K * nh + nu_ineq, nu) = 1;
192 qp.l(prm.K * nh + nu_ineq) = 0;
193 qp.u(prm.K * nh + nu_ineq) = std::numeric_limits<double>::infinity();
194
195 qp.P.template block<nu, nu>(0, 0) = pbm.W_u.asDiagonal();
196
197 qp.P(nu, nu) = prm.relax_cost;
198 qp.q(nu) = 0;
199}
200
244template<LieGroup X, Manifold U, diff::Type DT = diff::Type::Default>
245QuadraticProgram<-1, -1, double>
246asif_to_qp(const ASIFProblem<X, U> & pbm, const ASIFtoQPParams & prm, auto && f, auto && h, auto && bu)
247{
248 static constexpr int nh = std::invoke_result_t<decltype(h), double, X>::SizeAtCompileTime;
249
250 static_assert(Dof<X> > 0, "State space dimension must be static");
251 static_assert(Dof<U> > 0, "Input space dimension must be static");
252 static_assert(nh > 0, "Safe set dimension must be static");
253
254 const int nu_ineq = pbm.ulim.A.rows();
255 QuadraticProgram<-1, -1, double> qp;
256 asif_to_qp_allocate<X, U>(qp, prm.K, nu_ineq, nh);
258 qp, pbm, prm, std::forward<decltype(f)>(f), std::forward<decltype(h)>(h), std::forward<decltype(bu)>(bu));
259 return qp;
260}
261
262} // namespace smooth::feedback
void asif_to_qp_allocate(QuadraticProgram<-1, -1, double > &qp, std::size_t K, std::size_t nu_ineq, std::size_t nh)
Allocate QP matrices (part 1 of asif_to_qp())
Definition: asif_func.hpp:80
QuadraticProgram<-1, -1, double > asif_to_qp(const ASIFProblem< X, U > &pbm, const ASIFtoQPParams &prm, auto &&f, auto &&h, auto &&bu)
Convert an ASIFProblem to a QuadraticProgram.
Definition: asif_func.hpp:246
void asif_to_qp_update(QuadraticProgram<-1, -1, double > &qp, const ASIFProblem< X, U > &pbm, const ASIFtoQPParams &prm, auto &&f, auto &&h, auto &&bu)
Fill QP matrices (part 2 of asif_to_qp())
Definition: asif_func.hpp:106
Quadratic Program definition.
Active set invariance problem definition.
Definition: asif_func.hpp:42
ManifoldBounds< U > ulim
input bounds
Definition: asif_func.hpp:52
Eigen::Matrix< double, Dof< U >, 1 > W_u
weights on desired input
Definition: asif_func.hpp:50
double T
time horizon
Definition: asif_func.hpp:44
Parameters for asif_to_qp.
Definition: asif_func.hpp:59
double relax_cost
relaxation cost
Definition: asif_func.hpp:67
double dt
maximal integration time step
Definition: asif_func.hpp:65
std::size_t K
number of constraint instances (equally spaced over the time horizon)
Definition: asif_func.hpp:61
double alpha
barrier function time constant s.t. .
Definition: asif_func.hpp:63
Manifold constraint set.
Definition: common.hpp:19
Eigen::VectorXd u
Upper bound.
Definition: common.hpp:29
Eigen::VectorXd l
Lower bound.
Definition: common.hpp:27
Eigen::Matrix< double, -1, Dof< M > > A
Transformation matrix.
Definition: common.hpp:23
M c
Nominal point in constraint set.
Definition: common.hpp:25
Quadratic program definition.
Definition: qp.hpp:33
Eigen::Matrix< Scalar, N, N > P
Positive semi-definite square cost (only upper triangular part is used)
Definition: qp.hpp:35
Eigen::Matrix< Scalar, M, N > A
Inequality matrix.
Definition: qp.hpp:40
Eigen::Matrix< Scalar, M, 1 > u
Inequality upper bound.
Definition: qp.hpp:44
Eigen::Matrix< Scalar, M, 1 > l
Inequality lower bound.
Definition: qp.hpp:42
Eigen::Matrix< Scalar, N, 1 > q
Linear cost.
Definition: qp.hpp:37