blob: 98dccb2c8560218ed91bc7100a7c4ed496c4f230 [file] [log] [blame]
Austin Schuh03785132018-02-19 18:29:06 -08001#ifndef FRC971_CONTROL_LOOPS_DLQR_H_
2#define FRC971_CONTROL_LOOPS_DLQR_H_
3
4#include <Eigen/Dense>
5
6namespace frc971 {
7namespace controls {
8
Austin Schuhcb091712018-02-21 20:01:55 -08009template <int num_states, int num_inputs>
10int Controllability(const ::Eigen::Matrix<double, num_states, num_states> &A,
11 const ::Eigen::Matrix<double, num_states, num_inputs> &B) {
12 Eigen::Matrix<double, num_states, num_states * num_inputs> controllability;
13 controllability.block(0, 0, num_states, num_inputs) = B;
14
15 for (size_t i = 1; i < num_states; i++) {
16 controllability.block(0, i * num_inputs, num_states, num_inputs) =
17 A *
18 controllability.block(0, (i - 1) * num_inputs, num_states,
19 num_inputs);
20 }
21
22 return Eigen::FullPivLU<
23 Eigen::Matrix<double, num_states, num_states * num_inputs>>(
24 controllability)
25 .rank();
26}
27
Austin Schuh03785132018-02-19 18:29:06 -080028extern "C" {
29// Forward declaration for slicot fortran library.
30void sb02od_(char *DICO, char *JOBB, char *FACT, char *UPLO, char *JOBL,
31 char *SORT, long *N, long *M, long *P, double *A, long *LDA,
32 double *B, long *LDB, double *Q, long *LDQ, double *R, long *LDR,
33 double *L, long *LDL, double *RCOND, double *X, long *LDX,
34 double *ALFAR, double *ALFAI, double *BETA, double *S, long *LDS,
35 double *T, long *LDT, double *U, long *LDU, double *TOL,
36 long *IWORK, double *DWORK, long *LDWORK, long *BWORK, long *INFO);
37}
38
Austin Schuhcb091712018-02-21 20:01:55 -080039// Computes the optimal LQR controller K for the provided system and costs.
Austin Schuh03785132018-02-19 18:29:06 -080040template <int kN, int kM>
Austin Schuhcb091712018-02-21 20:01:55 -080041int dlqr(::Eigen::Matrix<double, kN, kN> A, ::Eigen::Matrix<double, kN, kM> B,
Austin Schuh03785132018-02-19 18:29:06 -080042 ::Eigen::Matrix<double, kN, kN> Q, ::Eigen::Matrix<double, kM, kM> R,
43 ::Eigen::Matrix<double, kM, kN> *K,
44 ::Eigen::Matrix<double, kN, kN> *S) {
45 *K = ::Eigen::Matrix<double, kM, kN>::Zero();
46 *S = ::Eigen::Matrix<double, kN, kN>::Zero();
47 // Discrete (not continuous)
48 char DICO = 'D';
49 // B and R are provided instead of G.
50 char JOBB = 'B';
51 // Not factored, Q and R are provide.
52 char FACT = 'N';
53 // Store the upper triangle of Q and R.
54 char UPLO = 'U';
55 // L is zero.
56 char JOBL = 'Z';
57 // Stable eigenvalues first in the sort order
58 char SORT = 'S';
59
60 long N = 4;
61 long M = 2;
62 // Not needed since FACT = N
63 long P = 0;
64
65 long LDL = 1;
66
67 double RCOND = 0.0;
68 ::Eigen::Matrix<double, kN, kN> X = ::Eigen::Matrix<double, kN, kN>::Zero();
69
70 double ALFAR[kN * 2];
71 double ALFAI[kN * 2];
72 double BETA[kN * 2];
73 memset(ALFAR, 0, kN * 2);
74 memset(ALFAI, 0, kN * 2);
75 memset(BETA, 0, kN * 2);
76
77 long LDS = 2 * kN + kM;
78 ::Eigen::Matrix<double, 2 * kN + kM, 2 *kN + kM> S_schur =
79 ::Eigen::Matrix<double, 2 * kN + kM, 2 * kN + kM>::Zero();
80
81 ::Eigen::Matrix<double, 2 * kN + kM, 2 *kN> T =
82 ::Eigen::Matrix<double, 2 * kN + kM, 2 * kN>::Zero();
83 long LDT = 2 * kN + kM;
84
85 ::Eigen::Matrix<double, 2 * kN, 2 *kN> U =
86 ::Eigen::Matrix<double, 2 * kN, 2 * kN>::Zero();
87 long LDU = 2 * kN;
88
89 double TOL = 0.0;
90
91 long IWORK[2 * kN > kM ? 2 * kN : kM];
92 memset(IWORK, 0, 2 * kN > kM ? 2 * kN : kM);
93
94 long LDWORK = 16 * kN + 3 * kM + 16;
95
96 double DWORK[LDWORK];
97 memset(DWORK, 0, LDWORK);
98
99 long INFO = 0;
100
101 long BWORK[2 * kN];
102 memset(BWORK, 0, 2 * kN);
103
104 // TODO(austin): I can't tell if anything here is transposed...
105 sb02od_(&DICO, &JOBB, &FACT, &UPLO, &JOBL, &SORT, &N, &M, &P, A.data(), &N,
106 B.data(), &N, Q.data(), &N, R.data(), &M, nullptr, &LDL, &RCOND,
107 X.data(), &N, ALFAR, ALFAI, BETA, S_schur.data(), &LDS, T.data(),
108 &LDT, U.data(), &LDU, &TOL, IWORK, DWORK, &LDWORK, BWORK, &INFO);
Austin Schuh03785132018-02-19 18:29:06 -0800109
110 *K = (R + B.transpose() * X * B).inverse() * B.transpose() * X * A;
111 if (S != nullptr) {
112 *S = X;
113 }
Austin Schuhcb091712018-02-21 20:01:55 -0800114
115 return INFO;
Austin Schuh03785132018-02-19 18:29:06 -0800116}
117
118} // namespace controls
119} // namespace frc971
120
121#endif // FRC971_CONTROL_LOOPS_DLQR_H_