CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

Estimation/StrapdownINS/ESKF/Visual/linearizeLandmark.mo

Download original .moGitHub source

Documentation: Estimation.StrapdownINS.ESKF.Visual.linearizeLandmark

within Estimation.StrapdownINS.ESKF.Visual;

function linearizeLandmark "Calibrated pinhole RGB-D observation in the right ESKF tangent"
  input NominalState nominal;
  input Real landmarkWorld_m[3];
  input Real rotationBodyCamera[3, 3];
  input Real cameraPositionBody_m[3];
  input Real intrinsics[4] "fx, fy, cx, cy";
  input Real minimumDepth_m = 0.1;
  output Real expected[3] "Pixel u, pixel v, optical-axis depth in metres";
  output Real navigationJacobian[3, 15];
  output Real landmarkJacobian[3, 3];
  output Boolean valid;
protected
  Real rotationWorldBody[3, 3];
  Real landmarkBody_m[3];
  Real landmarkCamera_m[3];
  Real projectionJacobian[3, 3];
  Real cameraNavigationJacobian[3, 15];
algorithm
  rotationWorldBody := LieGroups.SO3.Quat.to_DCM(nominal.quaternionWorldBody);
  landmarkBody_m := transpose(rotationWorldBody)
    * (landmarkWorld_m - nominal.positionWorldEnu_m);
  landmarkCamera_m := transpose(rotationBodyCamera)
    * (landmarkBody_m - cameraPositionBody_m);
  valid := minimumDepth_m > 0.0 and minimumDepth_m < FiniteMagnitudeLimit
    and intrinsics[1] > 0.0 and intrinsics[2] > 0.0
    and landmarkCamera_m[3] >= minimumDepth_m;
  for component in 1:3 loop
    valid := valid and abs(landmarkCamera_m[component]) < FiniteMagnitudeLimit;
  end for;
  for component in 1:4 loop
    valid := valid and abs(intrinsics[component]) < FiniteMagnitudeLimit;
  end for;
  expected := zeros(3);
  navigationJacobian := zeros(3, 15);
  landmarkJacobian := zeros(3, 3);
  if valid then
    expected := {intrinsics[1] * landmarkCamera_m[1] / landmarkCamera_m[3]
        + intrinsics[3],
      intrinsics[2] * landmarkCamera_m[2] / landmarkCamera_m[3] + intrinsics[4],
      landmarkCamera_m[3]};
    projectionJacobian := [intrinsics[1] / landmarkCamera_m[3], 0.0,
        -intrinsics[1] * landmarkCamera_m[1] / landmarkCamera_m[3]^2;
      0.0, intrinsics[2] / landmarkCamera_m[3],
        -intrinsics[2] * landmarkCamera_m[2] / landmarkCamera_m[3]^2;
      0.0, 0.0, 1.0];
    cameraNavigationJacobian := zeros(3, 15);
    cameraNavigationJacobian[:, 1:3] := -transpose(rotationBodyCamera);
    cameraNavigationJacobian[:, 7:9] := transpose(rotationBodyCamera)
      * LieGroups.SO3.Quat.wedge(landmarkBody_m);
    navigationJacobian := projectionJacobian * cameraNavigationJacobian;
    landmarkJacobian := projectionJacobian * transpose(rotationBodyCamera)
      * transpose(rotationWorldBody);
  end if;
end linearizeLandmark;