Program Listing for File quadrotor_dynamics.cpp

Return to documentation for file (src/bitrl/dynamics/quadrotor_dynamics.cpp)

#include "bitrl/dynamics/quadrotor_dynamics.h"
#include "bitrl/bitrl_consts.h"
#include "bitrl/utils/maths/math_utils.h"

#include <Eigen/Geometry> // need this for cross otherwise we get linking errors
#include <cmath>

namespace bitrl{
namespace dynamics {

QuadrotorDynamics::QuadrotorDynamics(QuadrotorDynamicsConfig config,
                      SysState<12>& state)
    :
      MotionModelDynamicsBase<SysState<12>,
                              DynamicsMatrixDescriptor,
                              RealVec>(state),
    config_(config)
{

    v_dot_ = RealColVec3d::Zero(3);
    omega_dot_ = RealColVec3d::Zero(3);
    euler_dot_ = RealColVec3d::Zero(3);

    rotation_mat_ = RealMat3d::Zero();
    euler_mat_ = RealMat3d::Zero();
}


QuadrotorDynamics::state_type&
QuadrotorDynamics::evaluate(const input_type& input ){
    integrate(input);
    return this->get_state();
}


void
QuadrotorDynamics::integrate(const RealVec& motor_w){

    translational_dynamics(motor_w);
    rotational_dynamics(motor_w);

    update_euler_angles_();
    update_rotation_matrix_();
    update_position_();
}

void
QuadrotorDynamics::update_position_(){

    const auto dt = config_.dt;
    const auto old_p = get_position_from_state_();
    const auto old_v = get_velocity_from_state_();
    RealColVec3d p = dt * rotation_mat_ * old_v + old_p;

    // update the position
    this -> get_state().set("x", p[0]);
    this -> get_state().set("y", p[1]);
    this -> get_state().set("z", p[2]);
}

void
QuadrotorDynamics::update_euler_angles_(){

    RealColVec3d euler_angles_old = get_euler_angles_from_state_();
    RealColVec3d old_omega = get_angular_velocity_from_state_();
    const auto dt = config_.dt;
    const auto phi = euler_angles_old[0];
    const auto theta = euler_angles_old[1];
    const auto psi = euler_angles_old[2];

    euler_mat_(0, 0) = 1.0;
    euler_mat_(0, 1) = std::sin(phi) * std::tan(theta);
    euler_mat_(0, 2) = std::cos(phi) * std::tan(theta);

    euler_mat_(1, 0) = 0.0;
    euler_mat_(1, 1) = std::cos(phi);
    euler_mat_(1, 2) = -std::sin(phi);

    euler_mat_(2, 0) = 0.0;
    euler_mat_(2, 1) = std::sin(phi) / std::cos(theta);
    euler_mat_(2, 2) = std::cos(phi) / std::cos(theta);

    RealColVec3d euler = dt * euler_mat_ * old_omega + euler_angles_old;

    euler_dot_ = (euler - euler_angles_old) / dt;

    this -> set_state_property("phi", euler[0]);
    this -> set_state_property("theta", euler[1]);
    this -> set_state_property("psi", euler[2]);
}

void
QuadrotorDynamics::update_rotation_matrix_(){

    RealColVec3d euler_angles_old = get_euler_angles_from_state_();
    const auto phi = euler_angles_old[0];
    const auto theta = euler_angles_old[1];
    const auto psi = euler_angles_old[2];


    auto c_theta = std::cos(theta);
    auto c_psi = std::cos(psi);
    auto c_phi = std::cos(phi);

    auto s_theta = std::sin(theta);
    auto s_psi = std::sin(psi);
    auto s_phi = std::sin(phi);

    rotation_mat_(0,0) = c_theta * c_psi;
    rotation_mat_(0,1) = s_psi * s_theta * c_psi - c_phi * s_psi;
    rotation_mat_(0,2) = c_phi * s_theta * c_psi + s_phi * s_psi;

    rotation_mat_(1,0) = c_theta * s_psi;
    rotation_mat_(1,1) = s_phi * s_theta * s_psi + c_phi * c_psi;
    rotation_mat_(1,2) = c_phi * s_theta * s_psi - s_phi * c_psi;

    rotation_mat_(2,0) = s_theta;
    rotation_mat_(2,1) = -s_phi * c_theta;
    rotation_mat_(2,2) = -c_phi * c_theta;
}

void
QuadrotorDynamics::rotational_dynamics(const RealVec& motor_w){

    const auto l = config_.l;
    const auto k_1 = config_.k_1;
    const auto k_2 = config_.k_2;
    const auto dt = config_.dt;

    RealColVec3d old_omega = get_angular_velocity_from_state_();

    auto p = old_omega[0];
    auto q = old_omega[1];
    auto r = old_omega[2];

    auto Jx = config_.Jx;
    auto Jy = config_.Jy;
    auto Jz = config_.Jz;

    RealColVec3d omega_cross_h = RealColVec3d::Zero(3);
    omega_cross_h[0] = ((Jy - Jz) / Jx) * q * r;
    omega_cross_h[1] = ((Jz - Jx) / Jy) * p * r;
    omega_cross_h[2] = ((Jx - Jy) / Jz) * p * q;

    // the torque vector
    RealColVec3d tau = RealColVec3d::Zero(3);

    // tau_phi = l*K_T*((omeag_4)^2 - (omeag_2)^2)
    tau[0] = l * k_1* (bitrl::utils::maths::sqr(motor_w[3]) - bitrl::utils::maths::sqr(motor_w[1]));
    tau[0] *= 1.0 / Jx;

    // tau_theta = l*K_T*((omeag_1)^2 - (omeag_3)^2)
    tau[1] = l * k_1* (bitrl::utils::maths::sqr(motor_w[0]) - bitrl::utils::maths::sqr(motor_w[2]));
    tau[1] = 1.0 / Jy;

    // tau_psi = Kd((omega_1)^2 - (omega_2)^2 + (omega_3)^2 - (omega_4)^2)
    tau[2] = k_2* (bitrl::utils::maths::sqr(motor_w[0])
                       - bitrl::utils::maths::sqr(motor_w[1])
                       + bitrl::utils::maths::sqr(motor_w[2])
                       - bitrl::utils::maths::sqr(motor_w[3]));
    tau[2] *= 1.0 / Jz;

    RealColVec3d omega = dt * omega_cross_h + dt * tau - old_omega;

    omega_dot_ = (omega - old_omega) / dt;

    // update the angular velocity
    this -> set_state_property("p", omega[0]);
    this -> set_state_property("q", omega[1]);
    this -> set_state_property("r", omega[2]);
}

void
QuadrotorDynamics::translational_dynamics(const RealVec& motor_w){

    const auto mass = config_.mass;
    const auto dt = config_.dt;

    // compute the gravity force
    RealColVec3d fg = RealColVec3d::Zero(3);

    if(config_.use_gravity){

        const auto phi_ = phi();
        const auto theta_ = theta();

        // we do not contain the mass constant so don't use it below
        fg[0] = -bitrl::consts::maths::G * std::sin(theta_);
        fg[1] =  bitrl::consts::maths::G * std::cos(theta_) * std::sin(phi_);
        fg[2] =  bitrl::consts::maths::G * std::cos(theta_) * std::cos(phi_);
    }

    // compute the total thurst force
    RealColVec3d ft = RealColVec3d::Zero(3);
    ft[2] = config_.k_1 * bitrl::utils::maths::sum_sqr(motor_w);

    RealColVec3d old_v = get_velocity_from_state_();
    RealColVec3d old_omega = get_angular_velocity_from_state_();

    // form the vector ωb/i × v
    RealColVec3d  omega_cross_v = old_omega.cross(old_v);

    // compute the velocity increment.
    // Note that the mass is dropped when accounting for gravity
    // as fg does not contain it
    RealColVec3d v = dt * omega_cross_v  +  dt *  fg - (1.0 / mass ) * dt * ft - old_v;

    // compute the time velocity derivative
    v_dot_ = (v - old_v) / dt;

    // update the old velocity
    this -> set_state_property("u", v[0]);
    this -> set_state_property("v", v[1]);
    this -> set_state_property("w", v[2]);

}

}
}