31 #include <Eigen/Cholesky>
33 #include <Eigen/Dense>
39 LqrController::LqrController() {}
45 _system_model = system_model;
47 const int p = getStateDimension();
48 const int q = getControlInputDimension();
50 setWeights(Eigen::MatrixXd::Identity(p, p), Eigen::MatrixXd::Identity(
q,
q));
56 if (!setWeightR(R)) ret_val =
false;
57 if (!setWeightQ(Q)) ret_val =
false;
63 if (!_system_model || R.rows() != _system_model->getInputDimension() || R.cols() != _system_model->getInputDimension())
return false;
70 if (!_system_model || Q.rows() != _system_model->getStateDimension() || Q.cols() != _system_model->getStateDimension())
return false;
75 bool LqrController::initialize(
const StateVector&
x, ReferenceTrajectoryInterface& expected_xref, ReferenceTrajectoryInterface& expected_uref,
76 const Duration& expected_dt,
const Time& t, ReferenceTrajectoryInterface* sref)
78 assert(
x.rows() == expected_xref.getDimension() &&
"Dimension mismatch in controller: current state x and reference");
83 PRINT_ERROR(
"LqrController: no system model provided. Cancelling.");
87 if (_system_model->isContinuousTime())
89 _discrete_time =
false;
90 PRINT_INFO(
"LqrController configured for continuous-time system dynamics.");
94 _discrete_time =
true;
95 PRINT_INFO(
"LqrController configured for discrete-time system dynamics.");
100 if (xref.rows() !=
x.rows())
102 PRINT_WARNING(
"LqrController currently supports only full state reference trajectories");
108 PRINT_INFO_COND(!_system_model->isLinear(),
"LQR is provided with a nonlinear model: linearizing model at target state...");
110 const int p = xref.rows();
111 const int q = uref.rows();
114 _system_model->getLinearA(xref, uref, _A);
116 _system_model->getLinearB(xref, uref, _B);
124 "Eigenvalues of the Hamiltonian are close to the imaginary axis. Numerically unstable results are expected.");
128 PRINT_WARNING_COND(!care_success || !_S.allFinite(),
"Riccati solving failed or NaN coefficients found in solution.");
137 SignalTargetInterface* signal_target, ReferenceTrajectoryInterface* sref, ReferenceTrajectoryInterface* xinit,
138 ReferenceTrajectoryInterface* uinit,
const std::string& ns)
140 const int q = uref.getDimension();
147 if (!initialize(
x, xref, uref, dt, t, sref))
155 xref.getReference(t, xref_vec);
157 uref.getReference(t, uref_vec);
159 StateVector state_error = xref_vec -
x;
161 u = _K * state_error + uref_vec;
163 if (signal_target && _publish_error)
165 signal_target->sendMeasurement(ns +
"controller/error_norml2", t.toSec(), {state_error.norm()});
170 u_sequence->add(0.0, u);
171 x_sequence->add(0.0,
x);
176 void LqrController::getAvailableSignals(SignalTargetInterface& signal_target,
const std::string& ns)
const
180 signal_target.registerMeasurement(ns +
"controller/error_norml2", 1);
184 void LqrController::reset() { _initialized =
false; }
186 #ifdef MESSAGE_SUPPORT
187 void LqrController::toMessage(corbo::messages::LqrController& message)
const
189 if (_system_model) _system_model->toMessage(*message.mutable_system_model());
194 Eigen::VectorXd Qdiag = _Q.diagonal();
195 message.mutable_q()->Resize(Qdiag.size(), 0);
198 message.set_q_diagonal_only(
true);
202 message.mutable_q()->Resize(_Q.rows() * _Q.cols(), 0);
205 message.set_q_diagonal_only(
false);
211 Eigen::VectorXd Rdiag = _R.diagonal();
212 message.mutable_r()->Resize(Rdiag.size(), 0);
215 message.set_r_diagonal_only(
true);
219 message.mutable_r()->Resize(_R.rows() * _R.cols(), 0);
222 message.set_r_diagonal_only(
false);
226 message.set_publish_error(_publish_error);
229 void LqrController::fromMessage(
const corbo::messages::LqrController& message, std::stringstream* issues)
231 _system_model.reset();
234 if (!message.has_system_model())
236 if (issues) *issues <<
"LqrController: no system model specified.\n";
242 util::get_oneof_field_type_expand_isolated(message.system_model(),
"system_dynamics", type,
false, 1);
247 dynamics->fromMessage(message.system_model(), issues);
248 setSystemModel(dynamics);
252 if (issues) *issues <<
"LqrController: unknown system model specified.\n";
256 const int p = dynamics->getStateDimension();
257 const int q = dynamics->getInputDimension();
260 if (message.q_diagonal_only())
262 if (p == message.q_size())
264 Eigen::MatrixXd Q =
Eigen::Map<
const Eigen::Matrix<double, -1, 1>>(message.q().data(), message.q_size()).asDiagonal();
265 if (!setWeightQ(Q) && issues) *issues <<
"LqrController: invalid size of weight matrix Q: it shout be [" << p <<
" x " << p <<
"].\n";
268 *issues <<
"LqrController: invalid size of weight matrix diag(Q): it shout be [ 1 x " << p <<
"].\n";
272 if (p * p == message.q_size())
275 *issues <<
"LqrController: invalid size of weight matrix Q: it shout be [" << p <<
" x " << p <<
"].\n";
278 *issues <<
"LqrController: invalid size of weight matrix Q: it shout be [" << p <<
" x " << p <<
"].\n";
281 if (message.r_diagonal_only())
283 if (
q == message.r_size())
285 Eigen::MatrixXd R =
Eigen::Map<
const Eigen::Matrix<double, -1, 1>>(message.r().data(), message.r_size()).asDiagonal();
286 if (!setWeightR(R) && issues) *issues <<
"LqrController: invalid size of weight matrix R: it shout be [" <<
q <<
" x " <<
q <<
"].\n";
289 *issues <<
"LqrController: invalid size of weight matrix diag(R): it shout be [ 1 x " <<
q <<
"].\n";
293 if (
q *
q == message.r_size())
296 *issues <<
"LqrController: invalid size of weight matrix R: it shout be [" <<
q <<
" x " <<
q <<
"].\n";
299 *issues <<
"LqrController: invalid size of weight matrix R: it shout be [" <<
q <<
" x " <<
q <<
"].\n";
303 _publish_error = message.publish_error();