// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #pragma once #include #include #include "Eigen/Cholesky" #include "frc/DARE.h" #include "frc/StateSpaceUtil.h" #include "frc/controller/LinearQuadraticRegulator.h" #include "frc/fmt/Eigen.h" #include "frc/system/Discretization.h" #include "unsupported/Eigen/MatrixFunctions" #include "wpimath/MathShared.h" namespace frc { template template LinearQuadraticRegulator::LinearQuadraticRegulator( const LinearSystem& plant, const StateArray& Qelems, const InputArray& Relems, units::second_t dt) : LinearQuadraticRegulator(plant.A(), plant.B(), Qelems, Relems, dt) {} template LinearQuadraticRegulator::LinearQuadraticRegulator( const Matrixd& A, const Matrixd& B, const StateArray& Qelems, const InputArray& Relems, units::second_t dt) : LinearQuadraticRegulator(A, B, MakeCostMatrix(Qelems), MakeCostMatrix(Relems), dt) {} template LinearQuadraticRegulator::LinearQuadraticRegulator( const Matrixd& A, const Matrixd& B, const Matrixd& Q, const Matrixd& R, units::second_t dt) { Matrixd discA; Matrixd discB; DiscretizeAB(A, B, dt, &discA, &discB); if (!IsStabilizable(discA, discB)) { std::string msg = fmt::format( "The system passed to the LQR is uncontrollable!\n\nA =\n{}\nB " "=\n{}\n", discA, discB); wpi::math::MathSharedStore::ReportError(msg); throw std::invalid_argument(msg); } Matrixd S = DARE(discA, discB, Q, R); // K = (BᵀSB + R)⁻¹BᵀSA m_K = (discB.transpose() * S * discB + R) .llt() .solve(discB.transpose() * S * discA); Reset(); } template LinearQuadraticRegulator::LinearQuadraticRegulator( const Matrixd& A, const Matrixd& B, const Matrixd& Q, const Matrixd& R, const Matrixd& N, units::second_t dt) { Matrixd discA; Matrixd discB; DiscretizeAB(A, B, dt, &discA, &discB); Matrixd S = DARE(discA, discB, Q, R, N); // K = (BᵀSB + R)⁻¹(BᵀSA + Nᵀ) m_K = (discB.transpose() * S * discB + R) .llt() .solve(discB.transpose() * S * discA + N.transpose()); Reset(); } template typename LinearQuadraticRegulator::InputVector LinearQuadraticRegulator::Calculate(const StateVector& x) { m_u = m_K * (m_r - x); return m_u; } template typename LinearQuadraticRegulator::InputVector LinearQuadraticRegulator::Calculate(const StateVector& x, const StateVector& nextR) { m_r = nextR; return Calculate(x); } template template void LinearQuadraticRegulator::LatencyCompensate( const LinearSystem& plant, units::second_t dt, units::second_t inputDelay) { Matrixd discA; Matrixd discB; DiscretizeAB(plant.A(), plant.B(), dt, &discA, &discB); m_K = m_K * (discA - discB * m_K).pow(inputDelay / dt); } } // namespace frc