File runge-kutta.hpp
File List > illixr > runge-kutta.hpp
Go to the documentation of this file
#pragma once
#include "data_format/proper_quaternion.hpp"
#ifdef __ANDROID__
# include
#else
# include
#endif
#include
namespace ILLIXR {
const data_format::proper_quaterniond dq_0(1., 0., 0., 0.);
const Eigen::Vector3d Gravity(0.0, 0.0, 9.81);
inline Eigen::Matrix3d symmetric_skew(const Eigen::Vector3d& vec) {
Eigen::Matrix3d skew_q;
skew_q << 0, -vec[2], vec[1], vec[2], 0, -vec[0], -vec[1], vec[0], 0;
return skew_q;
}
inline Eigen::Matrix4d makeOmega(const Eigen::Vector3d& w) {
Eigen::Matrix4d omega = Eigen::Matrix4d::Zero();
omega.block<3, 3>(0, 0) = -symmetric_skew(w);
omega.block<1, 3>(3, 0) = -w.transpose();
omega.block<3, 1>(0, 3) = w;
return omega;
}
inline data_format::proper_quaterniond delta_q(const data_format::proper_quaterniond& k_n) {
data_format::proper_quaterniond dq(dq_0 + 0.5 * k_n);
dq.normalize();
return dq;
}
inline data_format::proper_quaterniond q_dot(const Eigen::Vector3d& av, const data_format::proper_quaterniond& dq) {
return data_format::proper_quaterniond(Eigen::Vector4d(0.5 * makeOmega(av) * dq.asVector()));
}
inline Eigen::Vector3d p_dot(const Eigen::Vector3d& iv, const Eigen::Vector3d& k_n) {
return Eigen::Vector3d(iv + 0.5 * k_n);
}
inline Eigen::Vector3d v_dot(const data_format::proper_quaterniond& dq, const data_format::proper_quaterniond& q,
const Eigen::Vector3d& l_acc) {
data_format::proper_quaterniond temp = q * dq;
temp.normalize();
return temp.toRotationMatrix() * l_acc - Gravity;
}
template<typename T>
inline T solve(const T& yn, const T& k1, const T& k2, const T& k3, const T& k4) {
return yn + (k1 + 2. * (k2 + k3) + k4) / 6.;
}
struct state_plus {
data_format::proper_quaterniond orientation;
Eigen::Vector3d velocity;
Eigen::Vector3d position;
[[maybe_unused]] state_plus(const data_format::proper_quaterniond& pq, const Eigen::Vector3d& vel,
const Eigen::Vector3d& pos)
: orientation(pq)
, velocity(vel)
, position(pos) { }
[[maybe_unused]] state_plus(const Eigen::Quaterniond& pq, const Eigen::Vector3d& vel, const Eigen::Vector3d& pos)
: orientation(pq)
, velocity(vel)
, position(pos) { }
state_plus() = default;
};
std::ostream& operator<<(std::ostream& os, const state_plus& sp) {
os << "Quat " << sp.orientation << std::endl;
os << "Vel " << sp.velocity << std::endl;
os << "Pos " << sp.position << std::endl;
return os;
}
state_plus predict_mean_rk4(double dt, const state_plus& sp, const Eigen::Vector3d& ang_vel, const Eigen::Vector3d& linear_acc,
const Eigen::Vector3d& ang_vel2, const Eigen::Vector3d& linear_acc2) {
Eigen::Vector3d av = ang_vel;
Eigen::Vector3d la = linear_acc;
const Eigen::Vector3d delta_av = (ang_vel2 - ang_vel) / dt;
const Eigen::Vector3d delta_la = (linear_acc2 - linear_acc) / dt;
// y0 ================
data_format::proper_quaterniond q_0 = sp.orientation; // initial orientation quaternion
Eigen::Vector3d p_0 = sp.position; // initial position vector
Eigen::Vector3d v_0 = sp.velocity; // initial velocity vector
// Calculate the RK4 coefficients
// solve orientation
// k1
data_format::proper_quaterniond k1_q = q_dot(av, dq_0) * dt;
av += 0.5 * delta_av * dt;
// k2
data_format::proper_quaterniond dq_1 = delta_q(k1_q);
data_format::proper_quaterniond k2_q = q_dot(av, dq_1) * dt;
// k3
data_format::proper_quaterniond dq_2 = delta_q(k2_q);
data_format::proper_quaterniond k3_q = q_dot(av, dq_2) * dt;
// k4
av += 0.5 * delta_av * dt;
data_format::proper_quaterniond dq_3 = delta_q(2. * k3_q);
data_format::proper_quaterniond k4_q = q_dot(av, dq_3) * dt;
// solve velocity
// k1
Eigen::Vector3d k1_v = v_dot(dq_0, q_0, la) * dt;
// k2
la += 0.5 * delta_la * dt;
Eigen::Vector3d k2_v = v_dot(dq_1, q_0, la) * dt;
// k3
Eigen::Vector3d k3_v = v_dot(dq_2, q_0, la) * dt;
// k4
la += 0.5 * delta_la * dt;
Eigen::Vector3d k4_v = v_dot(dq_3, q_0, la) * dt;
// solve position
// k1
Eigen::Vector3d k1_p = v_0 * dt;
// k2
Eigen::Vector3d k2_p = p_dot(v_0, k1_v) * dt;
// k3
Eigen::Vector3d k3_p = p_dot(v_0, k2_v) * dt;
// k4
Eigen::Vector3d k4_p = p_dot(v_0, 2. * k3_v) * dt;
// y+dt ================
state_plus state_plus;
data_format::proper_quaterniond dq = solve(dq_0, k1_q, k2_q, k3_q, k4_q);
dq.normalize();
state_plus.orientation = q_0 * dq;
state_plus.orientation.normalize();
state_plus.position = solve(p_0, k1_p, k2_p, k3_p, k4_p);
state_plus.velocity = solve(v_0, k1_v, k2_v, k3_v, k4_v);
return state_plus;
}
} // namespace ILLIXR