{
  "name": "ardupilot sitl",
  "version": "1",
  "source": "Hazards restated from what ArduPilot's own autotest suite asserts about a flight (Tools/autotest/vehicle_test_suite.py: wait_altitude, wait_location, wait_mode, the end-of-test audit that the vehicle is disarmed and back where it started) and from the terrain-following hazard Plane.TerrainRally is named for. The faults are ArduPilot's own SITL failure parameters (libraries/SITL), graded; which hazards each is aimed at is this file's claim, and every catch is re-indexed by the check that actually failed.",
  "notes": "Two magnitudes per fault, to keep a sweep of thirty-odd tests inside an afternoon on one laptop. `unable_to_arm` is not gated: a vehicle that refuses to arm under a sensor fault is doing its job, and a test that fails there has caught the fault only in the sense that it never flew. `fence_breach` is declared and no check here evidences it: the suite checks fences through test-specific assertions this adapter reports as `test_assertion`, which is saying so rather than guessing. `position_divergence` is the suite's own hook comparing the vehicle's position estimate with the simulator's truth (150 m); it counts as navigation. `test_assertion` - a raise in a test's own body - is deliberately left unmapped: nothing says which hazard a free-form assertion evidences, so a catch through it stays listed as unconfirmed rather than being guessed into one.",
  "hazards": [
    {
      "id": "ground_impact",
      "name": "The vehicle struck the ground or terrain in flight",
      "gate": "fail"
    },
    {
      "id": "terrain_clearance_lost",
      "name": "Flew below its minimum height above terrain",
      "gate": "fail"
    },
    {
      "id": "altitude_deviation",
      "name": "Did not reach or hold a commanded altitude",
      "gate": "fail"
    },
    {
      "id": "navigation_deviation",
      "name": "Did not reach or follow a commanded location or path, or did not come back",
      "gate": "fail"
    },
    {
      "id": "speed_deviation",
      "name": "Did not reach or hold a commanded speed",
      "gate": "fail"
    },
    {
      "id": "attitude_excursion",
      "name": "Attitude left the commanded envelope",
      "gate": "fail"
    },
    {
      "id": "mode_transition_failure",
      "name": "A commanded or failsafe mode change did not happen",
      "gate": "fail"
    },
    {
      "id": "landing_failure",
      "name": "Did not land and disarm when it should have",
      "gate": "fail"
    },
    {
      "id": "left_armed_state",
      "name": "Motors still armed at the end of the flight",
      "gate": "fail"
    },
    {
      "id": "firmware_fault",
      "name": "The firmware stopped answering",
      "gate": "fail"
    },
    {
      "id": "fence_breach",
      "name": "Left the geofence",
      "gate": "fail"
    },
    {
      "id": "unable_to_arm",
      "name": "Refused to arm, or its estimator never became healthy",
      "gate": "ignore",
      "reason": "refusing to fly under a sensor fault is the safe outcome, not a hazard"
    }
  ],
  "operators": [
    {
      "name": "gps-lag",
      "kind": "lag",
      "magnitudes": [
        0.3,
        1.0
      ],
      "reaches": [
        "navigation_deviation",
        "terrain_clearance_lost",
        "ground_impact",
        "landing_failure"
      ],
      "rationale": "SIM_GPS1_LAG_MS 370 and 1000 ms: a position the controller acts on late"
    },
    {
      "name": "gps-dropout",
      "kind": "dropout",
      "magnitudes": [
        0.5,
        0.9
      ],
      "reaches": [
        "navigation_deviation",
        "mode_transition_failure",
        "landing_failure",
        "fence_breach"
      ],
      "rationale": "SIM_GPS1_BYTELOS 47.5 and 85.5 %: fixes that arrive broken or not at all"
    },
    {
      "name": "gps-altitude-drift",
      "kind": "drift",
      "magnitudes": [
        0.5,
        1.0
      ],
      "reaches": [
        "altitude_deviation",
        "terrain_clearance_lost",
        "ground_impact",
        "landing_failure"
      ],
      "rationale": "SIM_GPS1_DRFTALT 15 and 30 m: the GPS height walks away from the truth"
    },
    {
      "name": "loop-jitter",
      "kind": "unsteady",
      "magnitudes": [
        0.5,
        1.0
      ],
      "reaches": [
        "attitude_excursion",
        "altitude_deviation",
        "navigation_deviation"
      ],
      "rationale": "SIM_TIME_JITTER 2.5 and 5 ms of main-loop jitter"
    },
    {
      "name": "imu-noise",
      "kind": "degrade",
      "magnitudes": [
        0.5,
        1.0
      ],
      "reaches": [
        "attitude_excursion",
        "altitude_deviation",
        "ground_impact"
      ],
      "rationale": "SIM_ACC{1,2}_RND 5 and 10, SIM_GYR{1,2}_RND 20 and 40: the suite's own 'noisy', and twice it"
    },
    {
      "name": "thrust-loss",
      "kind": "sluggish",
      "magnitudes": [
        0.4,
        0.75
      ],
      "reaches": [
        "altitude_deviation",
        "speed_deviation",
        "terrain_clearance_lost",
        "ground_impact",
        "landing_failure"
      ],
      "rationale": "SIM_ENGINE_MUL 0.68 and 0.4 on every motor: a weaker vehicle"
    }
  ],
  "checks": {
    "ground_contact": [
      "ground_impact"
    ],
    "terrain_clearance": [
      "terrain_clearance_lost"
    ],
    "altitude": [
      "altitude_deviation"
    ],
    "navigation": [
      "navigation_deviation"
    ],
    "not_back_at_start": [
      "navigation_deviation"
    ],
    "speed": [
      "speed_deviation"
    ],
    "attitude": [
      "attitude_excursion"
    ],
    "mode": [
      "mode_transition_failure"
    ],
    "landing": [
      "landing_failure"
    ],
    "left_armed": [
      "left_armed_state"
    ],
    "firmware_died": [
      "firmware_fault"
    ],
    "arming": [
      "unable_to_arm"
    ],
    "estimator": [
      "unable_to_arm"
    ],
    "position_divergence": [
      "navigation_deviation"
    ]
  }
}
