lqr.h
Go to the documentation of this file.
1 /*******************************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2021, Qiayuan Liao
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *******************************************************************************/
33 
34 //
35 // Created by chenzheng on 3/20/21.
36 //
37 
38 #pragma once
39 
40 #include <iostream>
41 #include <Eigen/Dense>
42 #include "eigen_types.h"
43 
44 template <typename T>
45 class Lqr
46 {
47 public:
48  template <typename TA, typename TB, typename TQ, typename TR>
49  Lqr(const Eigen::MatrixBase<TA>& A, const Eigen::MatrixBase<TB>& B, const Eigen::MatrixBase<TQ>& Q,
50  const Eigen::MatrixBase<TR>& R)
51  : a_(A), b_(B), q_(Q), r_(R)
52  {
53  // check A
54  static_assert(TA::RowsAtCompileTime == TA::ColsAtCompileTime, "lqr: A should be square matrix");
55  // check B
56  static_assert(TB::RowsAtCompileTime == TA::RowsAtCompileTime, "lqr: B rows should be equal to A rows");
57  // check Q
58  static_assert(TQ::RowsAtCompileTime == TA::RowsAtCompileTime && TQ::ColsAtCompileTime == TA::ColsAtCompileTime,
59  "lqr: The rows and columns of Q should be equal to A");
60  // check R
61  static_assert(TR::RowsAtCompileTime == TB::ColsAtCompileTime && TR::ColsAtCompileTime == TB::ColsAtCompileTime,
62  "lqr: The rows and columns of R should be equal to the cols of B");
63 
64  k_.resize(TB::ColsAtCompileTime, TB::RowsAtCompileTime);
65  k_.setZero();
66  }
67 
68  bool solveRiccatiArimotoPotter(const Eigen::MatrixXd& A, const Eigen::MatrixXd& B, const Eigen::MatrixXd& Q,
69  const Eigen::MatrixXd& R, Eigen::MatrixXd& P)
70  {
71  int dim_x = A.rows();
72 
73  // set Hamilton matrix
74  Eigen::MatrixXd ham = Eigen::MatrixXd::Zero(2 * dim_x, 2 * dim_x);
75  ham << A, -B * R.inverse() * B.transpose(), -Q, -A.transpose();
76 
77  // calc eigenvalues and eigenvectors
78  Eigen::EigenSolver<Eigen::MatrixXd> eigs(ham);
79 
80  // extract stable eigenvectors into 'eigvec'
81  Eigen::MatrixXcd eigvec = Eigen::MatrixXcd::Zero(2 * dim_x, dim_x);
82  int j = 0;
83  for (int i = 0; i < 2 * dim_x; ++i)
84  {
85  if (eigs.eigenvalues()[i].real() < 0.)
86  {
87  eigvec.col(j) = eigs.eigenvectors().block(0, i, 2 * dim_x, 1);
88  ++j;
89  }
90  }
91 
92  // calc P with stable eigen vector matrix
93  Eigen::MatrixXcd vs_1, vs_2;
94  vs_1 = eigvec.block(0, 0, dim_x, dim_x);
95  vs_2 = eigvec.block(dim_x, 0, dim_x, dim_x);
96  P = (vs_2 * vs_1.inverse()).real();
97 
98  return true;
99  }
100 
101  bool computeK()
102  {
103  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > q_solver(q_);
104  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > r_solver(r_);
105  if (q_solver.info() != Eigen::Success || r_solver.info() != Eigen::Success)
106  return false;
107  // q (r) must be symmetric positive (semi) definite
108  for (int i = 0; i < q_solver.eigenvalues().cols(); ++i)
109  {
110  if (q_solver.eigenvalues()[i] < 0)
111  return false;
112  }
113  for (int i = 0; i < r_solver.eigenvalues().cols(); ++i)
114  {
115  if (r_solver.eigenvalues()[i] <= 0)
116  return false;
117  }
118  if (!isSymmetric(q_) || !isSymmetric(r_))
119  return false;
120 
121  DMat<T> p;
122  if (solveRiccatiArimotoPotter(a_, b_, q_, r_, p))
123  k_ = r_.inverse() * (b_.transpose() * p.transpose());
124  return true;
125  }
126 
127  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> getK()
128  {
129  return k_;
130  }
131 
132 private:
133  bool isSymmetric(DMat<T> m)
134  {
135  for (int i = 0; i < m.rows() - 1; ++i)
136  {
137  for (int j = i + 1; j < m.cols(); ++j)
138  {
139  if (m(i, j - i) != m(j - i, i))
140  return false;
141  }
142  }
143  return true;
144  }
145 
146  DMat<T> a_, b_, q_, r_, k_;
147 };
Lqr::solveRiccatiArimotoPotter
bool solveRiccatiArimotoPotter(const Eigen::MatrixXd &A, const Eigen::MatrixXd &B, const Eigen::MatrixXd &Q, const Eigen::MatrixXd &R, Eigen::MatrixXd &P)
Definition: lqr.h:99
Lqr::q_
DMat< T > q_
Definition: lqr.h:177
Lqr
Definition: lqr.h:45
Lqr::r_
DMat< T > r_
Definition: lqr.h:177
Lqr::isSymmetric
bool isSymmetric(DMat< T > m)
Definition: lqr.h:164
DMat
typename Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > DMat
Definition: eigen_types.h:146
eigen_types.h
Lqr::k_
DMat< T > k_
Definition: lqr.h:177
Lqr::getK
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > getK()
Definition: lqr.h:158
Lqr::b_
DMat< T > b_
Definition: lqr.h:177
Lqr::Lqr
Lqr(const Eigen::MatrixBase< TA > &A, const Eigen::MatrixBase< TB > &B, const Eigen::MatrixBase< TQ > &Q, const Eigen::MatrixBase< TR > &R)
Definition: lqr.h:80
Lqr::a_
DMat< T > a_
Definition: lqr.h:177
Lqr::computeK
bool computeK()
Definition: lqr.h:132


rm_common
Author(s):
autogenerated on Sun Apr 6 2025 02:22:01