CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

Estimation/PositionEstimator.mo

Download original .moGitHub source

Documentation: Estimation.PositionEstimator

within Estimation;
model PositionEstimator
  "Fixed-gain GPS/mocap position estimator with inertial propagation"
  parameter Real samplePeriod(unit="s") = 0.005;
  parameter Real gravity_m_s2(unit="m/s2") = 9.81;
  parameter Real initialPosition_m[3] = {0.0, 0.0, 0.0};
  parameter Real initialVelocity_m_s[3] = {0.0, 0.0, 0.0};
  parameter Real steadyStateGain[6, 3] = [
    0.05, 0.0, 0.0;
    0.0, 0.05, 0.0;
    0.0, 0.0, 0.05;
    0.03, 0.0, 0.0;
    0.0, 0.03, 0.0;
    0.0, 0.0, 0.03]
    "Fixed gain; upper rows correct position and lower rows correct velocity";

  input Real attitude_wb[4](start={1.0, 0.0, 0.0, 0.0})
    "Estimated scalar-first quaternion from body FLU to world ENU";
  input Real specificForce_b_m_s2[3](start={0.0, 0.0, gravity_m_s2})
    "Raw accelerometer specific force in body FLU [m/s2]";
  input Real measuredPosition_m[3](each start=0.0)
    "Local Cartesian GPS or mocap position in world ENU [m]";
  input Boolean measurementFresh(start=false)
    "True for exactly one estimator tick when a new valid measurement arrives";
  input Boolean reset(start=true);

  discrete output Real position_m[3](each start=0.0)
    "Estimated position in world ENU [m]";
  discrete output Real velocity_m_s[3](each start=0.0)
    "Estimated velocity in world ENU [m/s]";
  discrete output Real acceleration_m_s2[3](each start=0.0)
    "Estimated inertial acceleration in world ENU [m/s2]";
  discrete output Real positionResidual_m[3](each start=0.0)
    "Latest accepted position innovation [m]";
  discrete output Boolean correctionApplied(start=false);

protected
  discrete Real predictedPosition_m[3](each start=0.0);
  discrete Real predictedVelocity_m_s[3](each start=0.0);
  discrete Real stateCorrection[6](each start=0.0);
  discrete Real attitudeNorm(start=1.0);
  discrete Real normalizedAttitude[4](start={1.0, 0.0, 0.0, 0.0});

algorithm
  when sample(0.0, samplePeriod) then
    attitudeNorm := max(sqrt(
      attitude_wb[1] * attitude_wb[1]
        + attitude_wb[2] * attitude_wb[2]
        + attitude_wb[3] * attitude_wb[3]
        + attitude_wb[4] * attitude_wb[4]), 1.0e-10);
    normalizedAttitude := attitude_wb / attitudeNorm;
    acceleration_m_s2[1] :=
      (1.0 - 2.0 * (normalizedAttitude[3] * normalizedAttitude[3]
        + normalizedAttitude[4] * normalizedAttitude[4]))
        * specificForce_b_m_s2[1]
      + 2.0 * (normalizedAttitude[2] * normalizedAttitude[3]
        - normalizedAttitude[1] * normalizedAttitude[4])
        * specificForce_b_m_s2[2]
      + 2.0 * (normalizedAttitude[2] * normalizedAttitude[4]
        + normalizedAttitude[1] * normalizedAttitude[3])
        * specificForce_b_m_s2[3];
    acceleration_m_s2[2] :=
      2.0 * (normalizedAttitude[2] * normalizedAttitude[3]
        + normalizedAttitude[1] * normalizedAttitude[4])
        * specificForce_b_m_s2[1]
      + (1.0 - 2.0 * (normalizedAttitude[2] * normalizedAttitude[2]
        + normalizedAttitude[4] * normalizedAttitude[4]))
        * specificForce_b_m_s2[2]
      + 2.0 * (normalizedAttitude[3] * normalizedAttitude[4]
        - normalizedAttitude[1] * normalizedAttitude[2])
        * specificForce_b_m_s2[3];
    acceleration_m_s2[3] :=
      2.0 * (normalizedAttitude[2] * normalizedAttitude[4]
        - normalizedAttitude[1] * normalizedAttitude[3])
        * specificForce_b_m_s2[1]
      + 2.0 * (normalizedAttitude[3] * normalizedAttitude[4]
        + normalizedAttitude[1] * normalizedAttitude[2])
        * specificForce_b_m_s2[2]
      + (1.0 - 2.0 * (normalizedAttitude[2] * normalizedAttitude[2]
        + normalizedAttitude[3] * normalizedAttitude[3]))
        * specificForce_b_m_s2[3]
      - gravity_m_s2;
    predictedPosition_m := if reset then
      (if measurementFresh then measuredPosition_m else initialPosition_m)
      else pre(position_m) + pre(velocity_m_s) * samplePeriod
        + 0.5 * acceleration_m_s2 * samplePeriod * samplePeriod;
    predictedVelocity_m_s := if reset then initialVelocity_m_s
      else pre(velocity_m_s) + acceleration_m_s2 * samplePeriod;
    positionResidual_m := if not reset and measurementFresh then
      measuredPosition_m - predictedPosition_m else {0.0, 0.0, 0.0};
    stateCorrection[1] := steadyStateGain[1, 1] * positionResidual_m[1]
      + steadyStateGain[1, 2] * positionResidual_m[2]
      + steadyStateGain[1, 3] * positionResidual_m[3];
    stateCorrection[2] := steadyStateGain[2, 1] * positionResidual_m[1]
      + steadyStateGain[2, 2] * positionResidual_m[2]
      + steadyStateGain[2, 3] * positionResidual_m[3];
    stateCorrection[3] := steadyStateGain[3, 1] * positionResidual_m[1]
      + steadyStateGain[3, 2] * positionResidual_m[2]
      + steadyStateGain[3, 3] * positionResidual_m[3];
    stateCorrection[4] := steadyStateGain[4, 1] * positionResidual_m[1]
      + steadyStateGain[4, 2] * positionResidual_m[2]
      + steadyStateGain[4, 3] * positionResidual_m[3];
    stateCorrection[5] := steadyStateGain[5, 1] * positionResidual_m[1]
      + steadyStateGain[5, 2] * positionResidual_m[2]
      + steadyStateGain[5, 3] * positionResidual_m[3];
    stateCorrection[6] := steadyStateGain[6, 1] * positionResidual_m[1]
      + steadyStateGain[6, 2] * positionResidual_m[2]
      + steadyStateGain[6, 3] * positionResidual_m[3];
    position_m[1] := predictedPosition_m[1] + stateCorrection[1];
    position_m[2] := predictedPosition_m[2] + stateCorrection[2];
    position_m[3] := predictedPosition_m[3] + stateCorrection[3];
    velocity_m_s[1] := predictedVelocity_m_s[1] + stateCorrection[4];
    velocity_m_s[2] := predictedVelocity_m_s[2] + stateCorrection[5];
    velocity_m_s[3] := predictedVelocity_m_s[3] + stateCorrection[6];
    correctionApplied := measurementFresh;
  end when;
end PositionEstimator;