From cf506e59b09356cf600d33844fe80118eceb1c44 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Tue, 26 May 2026 11:16:05 -0500 Subject: [PATCH] nav --- common/params_keys.h | 6 + scripts/launch_onroad_desktop.sh | 109 +- selfdrive/controls/lib/desire_helper.py | 87 + .../controls/tests/test_navigation_desires.py | 113 + selfdrive/locationd/locationd.py | 26 + selfdrive/locationd/models/generated/car.cpp | 684 +++--- selfdrive/locationd/models/generated/car.h | 42 +- selfdrive/locationd/models/generated/pose.cpp | 1938 ++++++++--------- selfdrive/locationd/models/generated/pose.h | 26 +- selfdrive/selfdrived/selfdrived.py | 47 +- .../ui/layouts/settings/starpilot/lateral.py | 5 + selfdrive/ui/mici/onroad/hud_renderer.py | 3 + selfdrive/ui/onroad/hud_renderer.py | 4 + .../ui/onroad/starpilot/navigation_card.py | 384 ++++ selfdrive/ui/qt/onroad/hud.cc | 206 ++ selfdrive/ui/qt/onroad/hud.h | 19 + selfdrive/ui/ui.cc | 1 + selfdrive/ui/ui_state.py | 1 + .../assets/navigation/direction_arrive.png | Bin 0 -> 1246 bytes .../navigation/direction_arrive_left.png | Bin 0 -> 1581 bytes .../navigation/direction_arrive_right.png | Bin 0 -> 1528 bytes .../navigation/direction_arrive_straight.png | Bin 0 -> 1246 bytes .../assets/navigation/direction_close.png | Bin 0 -> 865 bytes .../assets/navigation/direction_continue.png | Bin 0 -> 1063 bytes .../navigation/direction_continue_left.png | Bin 0 -> 1400 bytes .../navigation/direction_continue_right.png | Bin 0 -> 1371 bytes .../direction_continue_slight_left.png | Bin 0 -> 1334 bytes .../direction_continue_slight_right.png | Bin 0 -> 1347 bytes .../direction_continue_straight.png | Bin 0 -> 1063 bytes .../navigation/direction_continue_uturn.png | Bin 0 -> 1780 bytes .../assets/navigation/direction_depart.png | Bin 0 -> 1234 bytes .../navigation/direction_depart_left.png | Bin 0 -> 1613 bytes .../navigation/direction_depart_right.png | Bin 0 -> 1538 bytes .../navigation/direction_depart_straight.png | Bin 0 -> 1234 bytes .../navigation/direction_end_of_road_left.png | Bin 0 -> 1439 bytes .../direction_end_of_road_right.png | Bin 0 -> 1456 bytes .../assets/navigation/direction_flag.png | Bin 0 -> 658 bytes .../assets/navigation/direction_fork.png | Bin 0 -> 2015 bytes .../assets/navigation/direction_fork_left.png | Bin 0 -> 1863 bytes .../navigation/direction_fork_right.png | Bin 0 -> 1841 bytes .../navigation/direction_fork_slight_left.png | Bin 0 -> 1800 bytes .../direction_fork_slight_right.png | Bin 0 -> 1805 bytes .../navigation/direction_fork_straight.png | Bin 0 -> 2473 bytes .../assets/navigation/direction_invalid.png | Bin 0 -> 1063 bytes .../navigation/direction_invalid_left.png | Bin 0 -> 1400 bytes .../navigation/direction_invalid_right.png | Bin 0 -> 1371 bytes .../direction_invalid_slight_left.png | Bin 0 -> 1334 bytes .../direction_invalid_slight_right.png | Bin 0 -> 1347 bytes .../navigation/direction_invalid_straight.png | Bin 0 -> 1063 bytes .../navigation/direction_invalid_uturn.png | Bin 0 -> 1780 bytes .../navigation/direction_merge_left.png | Bin 0 -> 1535 bytes .../navigation/direction_merge_right.png | Bin 0 -> 1484 bytes .../direction_merge_slight_left.png | Bin 0 -> 1765 bytes .../direction_merge_slight_right.png | Bin 0 -> 1699 bytes .../navigation/direction_merge_straight.png | Bin 0 -> 113 bytes .../navigation/direction_new_name_left.png | Bin 0 -> 1400 bytes .../navigation/direction_new_name_right.png | Bin 0 -> 1371 bytes .../direction_new_name_sharp_left.png | Bin 0 -> 1549 bytes .../direction_new_name_sharp_right.png | Bin 0 -> 1552 bytes .../direction_new_name_slight_left.png | Bin 0 -> 1334 bytes .../direction_new_name_slight_right.png | Bin 0 -> 1347 bytes .../direction_new_name_straight.png | Bin 0 -> 1063 bytes .../direction_notificaiton_right.png | Bin 0 -> 1371 bytes .../direction_notificaiton_sharp_right.png | Bin 0 -> 1551 bytes .../direction_notification_left.png | Bin 0 -> 1400 bytes .../direction_notification_right.png | Bin 0 -> 1371 bytes .../direction_notification_sharp_left.png | Bin 0 -> 1546 bytes .../direction_notification_slight_left.png | Bin 0 -> 1334 bytes .../direction_notification_slight_right.png | Bin 0 -> 1347 bytes .../direction_notification_straight.png | Bin 0 -> 1063 bytes .../navigation/direction_off_ramp_left.png | Bin 0 -> 1524 bytes .../navigation/direction_off_ramp_right.png | Bin 0 -> 1580 bytes .../direction_off_ramp_slight_left.png | Bin 0 -> 1478 bytes .../direction_off_ramp_slight_right.png | Bin 0 -> 1519 bytes .../navigation/direction_on_ramp_left.png | Bin 0 -> 1400 bytes .../navigation/direction_on_ramp_right.png | Bin 0 -> 1371 bytes .../direction_on_ramp_sharp_left.png | Bin 0 -> 1549 bytes .../direction_on_ramp_sharp_right.png | Bin 0 -> 1551 bytes .../direction_on_ramp_slight_left.png | Bin 0 -> 1334 bytes .../direction_on_ramp_slight_right.png | Bin 0 -> 1346 bytes .../navigation/direction_on_ramp_straight.png | Bin 0 -> 1063 bytes .../assets/navigation/direction_rotary.png | Bin 0 -> 1906 bytes .../navigation/direction_rotary_left.png | Bin 0 -> 1543 bytes .../navigation/direction_rotary_right.png | Bin 0 -> 1743 bytes .../direction_rotary_sharp_left.png | Bin 0 -> 1532 bytes .../direction_rotary_sharp_right.png | Bin 0 -> 1855 bytes .../direction_rotary_slight_left.png | Bin 0 -> 1699 bytes .../direction_rotary_slight_right.png | Bin 0 -> 1821 bytes .../navigation/direction_rotary_straight.png | Bin 0 -> 1736 bytes .../navigation/direction_roundabout.png | Bin 0 -> 1906 bytes .../navigation/direction_roundabout_left.png | Bin 0 -> 1543 bytes .../navigation/direction_roundabout_right.png | Bin 0 -> 1743 bytes .../direction_roundabout_sharp_left.png | Bin 0 -> 1532 bytes .../direction_roundabout_sharp_right.png | Bin 0 -> 1855 bytes .../direction_roundabout_slight_left.png | Bin 0 -> 1702 bytes .../direction_roundabout_slight_right.png | Bin 0 -> 1821 bytes .../direction_roundabout_straight.png | Bin 0 -> 1736 bytes .../assets/navigation/direction_turn_left.png | Bin 0 -> 1400 bytes .../navigation/direction_turn_right.png | Bin 0 -> 1371 bytes .../navigation/direction_turn_sharp_left.png | Bin 0 -> 1546 bytes .../navigation/direction_turn_sharp_right.png | Bin 0 -> 1551 bytes .../navigation/direction_turn_slight_left.png | Bin 0 -> 1334 bytes .../direction_turn_slight_right.png | Bin 0 -> 1347 bytes .../navigation/direction_turn_straight.png | Bin 0 -> 1063 bytes .../assets/navigation/direction_updown.png | Bin 0 -> 1327 bytes .../assets/navigation/direction_uturn.png | Bin 0 -> 1780 bytes starpilot/common/safe_mode.py | 1 + starpilot/navigation/destination_store.py | 104 + starpilot/navigation/navigationd.py | 306 +++ starpilot/navigation/route_engine.py | 434 ++++ .../navigation/test_destination_store.py | 48 + starpilot/navigation/test_route_engine.py | 153 ++ .../the_pond/assets/components/sidebar.js | 1 + .../tools/device_settings_layout.json | 8 + starpilot/system/the_pond/the_pond.py | 14 +- starpilot/ui/qt/offroad/lateral_settings.cc | 1 + starpilot/ui/qt/offroad/lateral_settings.h | 2 +- system/manager/process_config.py | 6 +- tools/replay/fake_nav_demo.py | 168 ++ 119 files changed, 3590 insertions(+), 1357 deletions(-) create mode 100644 selfdrive/controls/tests/test_navigation_desires.py create mode 100644 selfdrive/ui/onroad/starpilot/navigation_card.py create mode 100644 starpilot/assets/navigation/direction_arrive.png create mode 100644 starpilot/assets/navigation/direction_arrive_left.png create mode 100644 starpilot/assets/navigation/direction_arrive_right.png create mode 100644 starpilot/assets/navigation/direction_arrive_straight.png create mode 100644 starpilot/assets/navigation/direction_close.png create mode 100644 starpilot/assets/navigation/direction_continue.png create mode 100644 starpilot/assets/navigation/direction_continue_left.png create mode 100644 starpilot/assets/navigation/direction_continue_right.png create mode 100644 starpilot/assets/navigation/direction_continue_slight_left.png create mode 100644 starpilot/assets/navigation/direction_continue_slight_right.png create mode 100644 starpilot/assets/navigation/direction_continue_straight.png create mode 100644 starpilot/assets/navigation/direction_continue_uturn.png create mode 100644 starpilot/assets/navigation/direction_depart.png create mode 100644 starpilot/assets/navigation/direction_depart_left.png create mode 100644 starpilot/assets/navigation/direction_depart_right.png create mode 100644 starpilot/assets/navigation/direction_depart_straight.png create mode 100644 starpilot/assets/navigation/direction_end_of_road_left.png create mode 100644 starpilot/assets/navigation/direction_end_of_road_right.png create mode 100644 starpilot/assets/navigation/direction_flag.png create mode 100644 starpilot/assets/navigation/direction_fork.png create mode 100644 starpilot/assets/navigation/direction_fork_left.png create mode 100644 starpilot/assets/navigation/direction_fork_right.png create mode 100644 starpilot/assets/navigation/direction_fork_slight_left.png create mode 100644 starpilot/assets/navigation/direction_fork_slight_right.png create mode 100644 starpilot/assets/navigation/direction_fork_straight.png create mode 100644 starpilot/assets/navigation/direction_invalid.png create mode 100644 starpilot/assets/navigation/direction_invalid_left.png create mode 100644 starpilot/assets/navigation/direction_invalid_right.png create mode 100644 starpilot/assets/navigation/direction_invalid_slight_left.png create mode 100644 starpilot/assets/navigation/direction_invalid_slight_right.png create mode 100644 starpilot/assets/navigation/direction_invalid_straight.png create mode 100644 starpilot/assets/navigation/direction_invalid_uturn.png create mode 100644 starpilot/assets/navigation/direction_merge_left.png create mode 100644 starpilot/assets/navigation/direction_merge_right.png create mode 100644 starpilot/assets/navigation/direction_merge_slight_left.png create mode 100644 starpilot/assets/navigation/direction_merge_slight_right.png create mode 100644 starpilot/assets/navigation/direction_merge_straight.png create mode 100644 starpilot/assets/navigation/direction_new_name_left.png create mode 100644 starpilot/assets/navigation/direction_new_name_right.png create mode 100644 starpilot/assets/navigation/direction_new_name_sharp_left.png create mode 100644 starpilot/assets/navigation/direction_new_name_sharp_right.png create mode 100644 starpilot/assets/navigation/direction_new_name_slight_left.png create mode 100644 starpilot/assets/navigation/direction_new_name_slight_right.png create mode 100644 starpilot/assets/navigation/direction_new_name_straight.png create mode 100644 starpilot/assets/navigation/direction_notificaiton_right.png create mode 100644 starpilot/assets/navigation/direction_notificaiton_sharp_right.png create mode 100644 starpilot/assets/navigation/direction_notification_left.png create mode 100644 starpilot/assets/navigation/direction_notification_right.png create mode 100644 starpilot/assets/navigation/direction_notification_sharp_left.png create mode 100644 starpilot/assets/navigation/direction_notification_slight_left.png create mode 100644 starpilot/assets/navigation/direction_notification_slight_right.png create mode 100644 starpilot/assets/navigation/direction_notification_straight.png create mode 100644 starpilot/assets/navigation/direction_off_ramp_left.png create mode 100644 starpilot/assets/navigation/direction_off_ramp_right.png create mode 100644 starpilot/assets/navigation/direction_off_ramp_slight_left.png create mode 100644 starpilot/assets/navigation/direction_off_ramp_slight_right.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_left.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_right.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_sharp_left.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_sharp_right.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_slight_left.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_slight_right.png create mode 100644 starpilot/assets/navigation/direction_on_ramp_straight.png create mode 100644 starpilot/assets/navigation/direction_rotary.png create mode 100644 starpilot/assets/navigation/direction_rotary_left.png create mode 100644 starpilot/assets/navigation/direction_rotary_right.png create mode 100644 starpilot/assets/navigation/direction_rotary_sharp_left.png create mode 100644 starpilot/assets/navigation/direction_rotary_sharp_right.png create mode 100644 starpilot/assets/navigation/direction_rotary_slight_left.png create mode 100644 starpilot/assets/navigation/direction_rotary_slight_right.png create mode 100644 starpilot/assets/navigation/direction_rotary_straight.png create mode 100644 starpilot/assets/navigation/direction_roundabout.png create mode 100644 starpilot/assets/navigation/direction_roundabout_left.png create mode 100644 starpilot/assets/navigation/direction_roundabout_right.png create mode 100644 starpilot/assets/navigation/direction_roundabout_sharp_left.png create mode 100644 starpilot/assets/navigation/direction_roundabout_sharp_right.png create mode 100644 starpilot/assets/navigation/direction_roundabout_slight_left.png create mode 100644 starpilot/assets/navigation/direction_roundabout_slight_right.png create mode 100644 starpilot/assets/navigation/direction_roundabout_straight.png create mode 100644 starpilot/assets/navigation/direction_turn_left.png create mode 100644 starpilot/assets/navigation/direction_turn_right.png create mode 100644 starpilot/assets/navigation/direction_turn_sharp_left.png create mode 100644 starpilot/assets/navigation/direction_turn_sharp_right.png create mode 100644 starpilot/assets/navigation/direction_turn_slight_left.png create mode 100644 starpilot/assets/navigation/direction_turn_slight_right.png create mode 100644 starpilot/assets/navigation/direction_turn_straight.png create mode 100644 starpilot/assets/navigation/direction_updown.png create mode 100644 starpilot/assets/navigation/direction_uturn.png create mode 100644 starpilot/navigation/destination_store.py create mode 100644 starpilot/navigation/navigationd.py create mode 100644 starpilot/navigation/route_engine.py create mode 100644 starpilot/navigation/test_destination_store.py create mode 100644 starpilot/navigation/test_route_engine.py create mode 100644 tools/replay/fake_nav_demo.py diff --git a/common/params_keys.h b/common/params_keys.h index 607f7b79d..74e210cd3 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -367,6 +367,9 @@ inline static std::unordered_map keys = { {"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0}}, {"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3}}, {"ManualUpdateInitiated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}}, + {"AMapKey1", {PERSISTENT | DONT_LOG, STRING, "", "", 0}}, + {"AMapKey2", {PERSISTENT | DONT_LOG, STRING, "", "", 0}}, + {"ApiCache_NavDestinations", {PERSISTENT, JSON, "[]", "[]"}}, {"MapAcceleration", {PERSISTENT, BOOL, "0", "0", 1}}, {"MapboxPublicKey", {PERSISTENT | DONT_LOG, STRING, "", "", 0}}, {"MapBoxRequests", {PERSISTENT, JSON, "{}", "{}"}}, @@ -376,6 +379,9 @@ inline static std::unordered_map keys = { {"MapGears", {PERSISTENT, BOOL, "0", "0", 2}}, {"MapsSelected", {PERSISTENT, STRING, "", "", 0}}, {"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}}, + {"NavDesiresAllowed", {PERSISTENT, BOOL, "0", "0", 2}}, + {"NavDestination", {PERSISTENT, STRING, "", ""}}, + {"NavInstructionState", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}}, {"NextMapSpeedLimit", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}}, {"VisionSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}}, {"VisionSpeedLimitConfidence", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}}, diff --git a/scripts/launch_onroad_desktop.sh b/scripts/launch_onroad_desktop.sh index 50d09ffeb..8cc879b8e 100755 --- a/scripts/launch_onroad_desktop.sh +++ b/scripts/launch_onroad_desktop.sh @@ -27,18 +27,20 @@ env_var_truthy() { usage() { cat <<'EOF' Usage: - ./onroad [jobs] (--c3 | --c4 | --raybig | --all | --replay-only) [--prefix name] + ./onroad [jobs] (--c3 | --c4 | --raybig | --all | --replay-only) [-nav] [--prefix name] Examples: - ./onroad --c3 f08912a233c1584f/2022-08-11--18-02-41/1 - ./onroad --c4 f08912a233c1584f/2022-08-11--18-02-41/1 --start 30 - ./onroad --all f08912a233c1584f/2022-08-11--18-02-41/1 + ./onroad --c3 + ./onroad --c4 --start 30 + ./onroad --c4 -nav + ./onroad --all ./onroad --replay-only --demo --no-vipc --no-loop Notes: - This is host/dev only. It uses the isolated host worktree and does not touch the device path. - A private comma connect route still requires tools/lib/auth.py before replay can download it. - Use multiple UI flags together if you want more than one desktop UI at once. + - -nav injects a fake navigation demo stream and blocks replay from publishing navInstruction/navRoute. EOF } @@ -53,7 +55,9 @@ REPLAY_ARGS=() UI_TARGETS=() LEGACY_UI_SELECTION="" REPLAY_ONLY=0 +NAV_DEMO=0 REPLAY_PID="" +NAV_PID="" UI_PIDS=() parse_args() { @@ -83,6 +87,10 @@ parse_args() { REPLAY_ONLY=1 shift ;; + -nav|--nav) + NAV_DEMO=1 + shift + ;; --ui) if [[ $# -lt 2 ]]; then echo "Missing value for --ui" >&2 @@ -194,6 +202,9 @@ cleanup() { if [[ -n "${REPLAY_PID}" ]]; then kill "${REPLAY_PID}" >/dev/null 2>&1 || true fi + if [[ -n "${NAV_PID}" ]]; then + kill "${NAV_PID}" >/dev/null 2>&1 || true + fi for pid in "${UI_PIDS[@]-}"; do if [[ -n "${pid}" ]]; then @@ -203,6 +214,9 @@ cleanup() { if [[ -n "${REPLAY_PID}" ]]; then wait "${REPLAY_PID}" >/dev/null 2>&1 || true fi + if [[ -n "${NAV_PID}" ]]; then + wait "${NAV_PID}" >/dev/null 2>&1 || true + fi if [[ -n "${OPENPILOT_PREFIX:-}" && "${OPENPILOT_PREFIX}" == desktop-onroad-* ]]; then echo "Cleaning up temporary prefix environment (${OPENPILOT_PREFIX})..." @@ -214,6 +228,68 @@ cleanup() { exit "${exit_code}" } +append_blocked_service_names() { + local existing="$1" + local required="$2" + local combined="${existing}" + + if [[ -n "${combined}" ]]; then + combined+=",${required}" + else + combined="${required}" + fi + + local deduped=() + local seen="," + local part="" + local parts=() + IFS=',' read -r -a parts <<< "${combined}" + for part in "${parts[@]-}"; do + part="${part// /}" + if [[ -z "${part}" ]]; then + continue + fi + if [[ "${seen}" != *",${part},"* ]]; then + deduped+=("${part}") + seen+="${part}," + fi + done + + local joined="" + for part in "${deduped[@]-}"; do + if [[ -n "${joined}" ]]; then + joined+="," + fi + joined+="${part}" + done + + printf '%s' "${joined}" +} + +ensure_nav_demo_replay_blocklist() { + local nav_services="navInstruction,navRoute" + local idx=0 + + for ((idx=0; idx<${#REPLAY_ARGS[@]}; idx++)); do + case "${REPLAY_ARGS[$idx]}" in + -b|--block) + if (( idx + 1 >= ${#REPLAY_ARGS[@]} )); then + echo "Missing value for ${REPLAY_ARGS[$idx]}" >&2 + exit 1 + fi + REPLAY_ARGS[$((idx + 1))]="$(append_blocked_service_names "${REPLAY_ARGS[$((idx + 1))]}" "${nav_services}")" + return + ;; + --block=*) + REPLAY_ARGS[$idx]="--block=$(append_blocked_service_names "${REPLAY_ARGS[$idx]#*=}" "${nav_services}")" + return + ;; + esac + done + + REPLAY_ARGS=(-b "${nav_services}" "${REPLAY_ARGS[@]}") +} + prepare_env() { source .venv/bin/activate @@ -238,6 +314,7 @@ prepare_env() { export SP_C4_FAKE_WIFI=0 export SP_RAYBIG_FAKE_WIFI=0 export SP_ALLOW_DESKTOP_FAKE_WIFI=0 + export SP_ONROAD_NAV_DEMO="${NAV_DEMO}" if [[ "$(uname -s)" == "Darwin" ]] || env_var_truthy "${ZMQ:-0}"; then export OPENPILOT_ZMQ_NAMESPACE="${PREFIX_ARG:-${OPENPILOT_ZMQ_NAMESPACE:-desktop-onroad-$$}}" @@ -250,6 +327,8 @@ prepare_env() { seed_params() { "${ROOT_DIR}/.venv/bin/python3" - <<'PY' +import os + from openpilot.common.params import Params from openpilot.system.version import terms_version, training_version @@ -260,6 +339,8 @@ params.put_bool("OpenpilotEnabledToggle", True) params.put_bool("IsDriverViewEnabled", False) params.put_bool("ForceOnroad", False) params.put_bool("ForceOffroad", False) +if os.getenv("SP_ONROAD_NAV_DEMO", "").lower() in {"1", "true", "yes", "on"}: + params.put_bool("NavigationUI", True) PY } @@ -302,6 +383,18 @@ launch_replay() { fi } +launch_nav_demo() { + echo "Starting fake nav demo publisher..." + "${ROOT_DIR}/.venv/bin/python3" "${ROOT_DIR}/tools/replay/fake_nav_demo.py" & + NAV_PID=$! + + sleep 0.5 + if ! kill -0 "${NAV_PID}" >/dev/null 2>&1; then + wait "${NAV_PID}" + return 1 + fi +} + launch_c3_ui() { local os_ext="linux" if [[ "$(uname -s)" == "Darwin" ]]; then @@ -339,6 +432,10 @@ else dedupe_ui_targets fi +if [[ "${NAV_DEMO}" == "1" ]]; then + ensure_nav_demo_replay_blocklist +fi + if [[ ${#REPLAY_ARGS[@]} -eq 0 ]]; then usage >&2 exit 1 @@ -378,6 +475,10 @@ seed_starpilot_theme echo "Starting replay: ${REPLAY_ARGS[*]}" launch_replay +if [[ "${NAV_DEMO}" == "1" ]]; then + launch_nav_demo +fi + if [[ ${#UI_TARGETS[@]} -eq 0 ]]; then echo "Replay is running without UI windows. Press Ctrl-C to stop." wait "${REPLAY_PID}" diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py index 7afe9163f..da3e90464 100644 --- a/selfdrive/controls/lib/desire_helper.py +++ b/selfdrive/controls/lib/desire_helper.py @@ -1,5 +1,8 @@ +import json + from cereal import log from openpilot.common.constants import CV +from openpilot.common.params import Params from openpilot.common.realtime import DT_MDL LaneChangeState = log.LaneChangeState @@ -40,6 +43,8 @@ TURN_DESIRES = { class DesireHelper: def __init__(self): + self.params = Params() + self.params_memory = Params(memory=True) self.lane_change_state = LaneChangeState.off self.lane_change_direction = LaneChangeDirection.none self.lane_change_timer = 0.0 @@ -51,6 +56,84 @@ class DesireHelper: self.lane_change_completed = False self.lane_change_wait_timer = 0.0 + self.nav_desires_allowed = False + self._nav_param_counter = -1 + self._nav_instruction_state_raw: object = None + self._nav_instruction_state: dict[str, object] = {} + + def _update_nav_params(self): + self._nav_param_counter += 1 + if self._nav_param_counter % 60 == 0: + self.nav_desires_allowed = self.params.get_bool("NavDesiresAllowed") + + raw = self.params_memory.get("NavInstructionState") or {} + if raw == self._nav_instruction_state_raw: + return + + self._nav_instruction_state_raw = raw + if not raw: + self._nav_instruction_state = {} + return + + if isinstance(raw, dict): + self._nav_instruction_state = raw + return + + if isinstance(raw, str): + try: + parsed = json.loads(raw) + self._nav_instruction_state = parsed if isinstance(parsed, dict) else {} + return + except Exception: + pass + + self._nav_instruction_state = {} + + @staticmethod + def _nav_keep_direction_is_clear(carstate, lane_change_direction): + return not ( + (lane_change_direction == LaneChangeDirection.left and carstate.leftBlindspot) or + (lane_change_direction == LaneChangeDirection.right and carstate.rightBlindspot) + ) + + @staticmethod + def _nav_torque_applied(carstate, lane_change_direction): + return carstate.steeringPressed and ( + (lane_change_direction == LaneChangeDirection.left and carstate.steeringTorque > 0) or + (lane_change_direction == LaneChangeDirection.right and carstate.steeringTorque < 0) + ) + + def _navigation_desire(self, carstate, lateral_active, starpilotPlan, starpilot_toggles): + self._update_nav_params() + if not self.nav_desires_allowed or not lateral_active or not bool(self._nav_instruction_state.get("valid", False)): + return log.Desire.none + + modifier = str(self._nav_instruction_state.get("maneuverModifier", "")) + if modifier == "": + return log.Desire.none + + if modifier == "slightLeft": + lane_change_direction = LaneChangeDirection.left + desired_lane_width = starpilotPlan.laneWidthLeft + nudgeless_allowed = starpilot_toggles.nudgeless and desired_lane_width >= starpilot_toggles.lane_detection_width + if not carstate.rightBlinker and self._nav_keep_direction_is_clear(carstate, lane_change_direction): + if self._nav_torque_applied(carstate, lane_change_direction) or nudgeless_allowed: + return log.Desire.keepLeft + elif modifier == "slightRight": + lane_change_direction = LaneChangeDirection.right + desired_lane_width = starpilotPlan.laneWidthRight + nudgeless_allowed = starpilot_toggles.nudgeless and desired_lane_width >= starpilot_toggles.lane_detection_width + if not carstate.leftBlinker and self._nav_keep_direction_is_clear(carstate, lane_change_direction): + if self._nav_torque_applied(carstate, lane_change_direction) or nudgeless_allowed: + return log.Desire.keepRight + elif modifier in ("left", "sharpLeft"): + if not carstate.rightBlinker and not carstate.leftBlindspot and carstate.vEgo < starpilot_toggles.minimum_lane_change_speed and not carstate.standstill: + return log.Desire.turnLeft + elif modifier in ("right", "sharpRight"): + if not carstate.leftBlinker and not carstate.rightBlindspot and carstate.vEgo < starpilot_toggles.minimum_lane_change_speed and not carstate.standstill: + return log.Desire.turnRight + + return log.Desire.none @staticmethod def get_lane_change_direction(CS): @@ -155,3 +238,7 @@ class DesireHelper: self.lane_change_completed = False self.lane_change_wait_timer = 0.0 + + nav_desire = self._navigation_desire(carstate, lateral_active, starpilotPlan, starpilot_toggles) + if nav_desire != log.Desire.none and self.lane_change_state == LaneChangeState.off: + self.desire = nav_desire diff --git a/selfdrive/controls/tests/test_navigation_desires.py b/selfdrive/controls/tests/test_navigation_desires.py new file mode 100644 index 000000000..6f47f0afc --- /dev/null +++ b/selfdrive/controls/tests/test_navigation_desires.py @@ -0,0 +1,113 @@ +from types import SimpleNamespace + +from cereal import log + +from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper, LaneChangeDirection, LaneChangeState + + +def make_car_state(**overrides): + defaults = { + "vEgo": 20.0, + "leftBlinker": False, + "rightBlinker": False, + "leftBlindspot": False, + "rightBlindspot": False, + "steeringPressed": False, + "steeringTorque": 0.0, + "standstill": False, + } + defaults.update(overrides) + return SimpleNamespace(**defaults) + + +def make_toggles(**overrides): + defaults = { + "lane_changes": True, + "lane_change_delay": 0.0, + "lane_detection_width": 3.0, + "minimum_lane_change_speed": 10.0, + "nudgeless": True, + "one_lane_change": False, + "use_turn_desires": False, + } + defaults.update(overrides) + return SimpleNamespace(**defaults) + + +def make_plan(**overrides): + defaults = { + "laneWidthLeft": 4.0, + "laneWidthRight": 4.0, + } + defaults.update(overrides) + return SimpleNamespace(**defaults) + +def test_nav_desires_keep_left_when_route_requests_it(): + helper = DesireHelper() + helper.nav_desires_allowed = True + helper._update_nav_params = lambda: None + helper._nav_instruction_state = {"valid": True, "maneuverModifier": "slightLeft"} + + helper.update( + make_car_state(vEgo=20.0), + True, + 0.0, + make_plan(laneWidthLeft=4.2), + make_toggles(nudgeless=True), + ) + + assert helper.desire == log.Desire.keepLeft + + +def test_nav_desires_turn_right_below_lane_change_speed(): + helper = DesireHelper() + helper.nav_desires_allowed = True + helper._update_nav_params = lambda: None + helper._nav_instruction_state = {"valid": True, "maneuverModifier": "right"} + + helper.update( + make_car_state(vEgo=5.0), + True, + 0.0, + make_plan(), + make_toggles(minimum_lane_change_speed=10.0), + ) + + assert helper.desire == log.Desire.turnRight + + +def test_nav_desires_do_not_override_lane_change_state_machine(): + helper = DesireHelper() + helper.nav_desires_allowed = True + helper._update_nav_params = lambda: None + helper._nav_instruction_state = {"valid": True, "maneuverModifier": "slightRight"} + helper.lane_change_state = LaneChangeState.laneChangeStarting + helper.lane_change_direction = LaneChangeDirection.left + helper.lane_change_ll_prob = 0.5 + + helper.update( + make_car_state(vEgo=25.0, leftBlinker=True), + True, + 0.5, + make_plan(), + make_toggles(), + ) + + assert helper.desire == log.Desire.laneChangeLeft + + +def test_nav_desires_disabled_leave_desire_unchanged(): + helper = DesireHelper() + helper.nav_desires_allowed = False + helper._update_nav_params = lambda: None + helper._nav_instruction_state = {"valid": True, "maneuverModifier": "left"} + + helper.update( + make_car_state(vEgo=5.0), + True, + 0.0, + make_plan(), + make_toggles(minimum_lane_change_speed=10.0), + ) + + assert helper.desire == log.Desire.none diff --git a/selfdrive/locationd/locationd.py b/selfdrive/locationd/locationd.py index 9c54a64f4..a8e6e5336 100755 --- a/selfdrive/locationd/locationd.py +++ b/selfdrive/locationd/locationd.py @@ -283,6 +283,7 @@ def main(): filter_initialized = False critcal_services = ["accelerometer", "gyroscope", "cameraOdometry"] observation_input_invalid = defaultdict(int) + last_inputs_diagnostics = None input_invalid_limit = {s: round(INPUT_INVALID_LIMIT * (SERVICE_LIST[s].frequency / 20.)) for s in critcal_services} input_invalid_threshold = {s: input_invalid_limit[s] - 0.5 for s in critcal_services} @@ -335,6 +336,31 @@ def main(): inputs_valid = sm.all_valid() and critical_service_inputs_valid sensors_valid = sensor_all_checks(acc_msgs, gyro_msgs, sensor_valid, sensor_recv_time, sensor_alive, SIMULATION) + invalid_services = [s for s, valid in sm.valid.items() if not valid] + over_threshold = { + s: round(float(observation_input_invalid[s]), 3) + for s in critcal_services + if observation_input_invalid[s] >= input_invalid_threshold[s] + } + inputs_diagnostics = { + "inputs_valid": inputs_valid, + "sensors_valid": sensors_valid, + "filter_initialized": filter_initialized, + "invalid_services": invalid_services, + "over_threshold": over_threshold, + } + if not inputs_valid and inputs_diagnostics != last_inputs_diagnostics: + cloudlog.event( + "locationdInputsInvalid", + error=True, + **inputs_diagnostics, + observation_input_invalid={s: round(float(observation_input_invalid[s]), 3) for s in critcal_services}, + observation_input_thresholds={s: float(input_invalid_threshold[s]) for s in critcal_services}, + ) + elif inputs_valid and last_inputs_diagnostics is not None: + cloudlog.event("locationdInputsRecovered", **inputs_diagnostics) + last_inputs_diagnostics = None if inputs_valid else inputs_diagnostics + msg = estimator.get_msg(sensors_valid, inputs_valid, filter_initialized) pm.send("livePose", msg) diff --git a/selfdrive/locationd/models/generated/car.cpp b/selfdrive/locationd/models/generated/car.cpp index 1b1966bce..2c1ffcb59 100644 --- a/selfdrive/locationd/models/generated/car.cpp +++ b/selfdrive/locationd/models/generated/car.cpp @@ -45,326 +45,326 @@ const static double MAHA_THRESH_31 = 3.8414588206941227; * * * This file is part of 'ekf' * ******************************************************************************/ -void err_fun(double *nom_x, double *delta_x, double *out_5406094264205448922) { - out_5406094264205448922[0] = delta_x[0] + nom_x[0]; - out_5406094264205448922[1] = delta_x[1] + nom_x[1]; - out_5406094264205448922[2] = delta_x[2] + nom_x[2]; - out_5406094264205448922[3] = delta_x[3] + nom_x[3]; - out_5406094264205448922[4] = delta_x[4] + nom_x[4]; - out_5406094264205448922[5] = delta_x[5] + nom_x[5]; - out_5406094264205448922[6] = delta_x[6] + nom_x[6]; - out_5406094264205448922[7] = delta_x[7] + nom_x[7]; - out_5406094264205448922[8] = delta_x[8] + nom_x[8]; +void err_fun(double *nom_x, double *delta_x, double *out_1976458697034392713) { + out_1976458697034392713[0] = delta_x[0] + nom_x[0]; + out_1976458697034392713[1] = delta_x[1] + nom_x[1]; + out_1976458697034392713[2] = delta_x[2] + nom_x[2]; + out_1976458697034392713[3] = delta_x[3] + nom_x[3]; + out_1976458697034392713[4] = delta_x[4] + nom_x[4]; + out_1976458697034392713[5] = delta_x[5] + nom_x[5]; + out_1976458697034392713[6] = delta_x[6] + nom_x[6]; + out_1976458697034392713[7] = delta_x[7] + nom_x[7]; + out_1976458697034392713[8] = delta_x[8] + nom_x[8]; } -void inv_err_fun(double *nom_x, double *true_x, double *out_7302786751934147898) { - out_7302786751934147898[0] = -nom_x[0] + true_x[0]; - out_7302786751934147898[1] = -nom_x[1] + true_x[1]; - out_7302786751934147898[2] = -nom_x[2] + true_x[2]; - out_7302786751934147898[3] = -nom_x[3] + true_x[3]; - out_7302786751934147898[4] = -nom_x[4] + true_x[4]; - out_7302786751934147898[5] = -nom_x[5] + true_x[5]; - out_7302786751934147898[6] = -nom_x[6] + true_x[6]; - out_7302786751934147898[7] = -nom_x[7] + true_x[7]; - out_7302786751934147898[8] = -nom_x[8] + true_x[8]; +void inv_err_fun(double *nom_x, double *true_x, double *out_8774680380747325588) { + out_8774680380747325588[0] = -nom_x[0] + true_x[0]; + out_8774680380747325588[1] = -nom_x[1] + true_x[1]; + out_8774680380747325588[2] = -nom_x[2] + true_x[2]; + out_8774680380747325588[3] = -nom_x[3] + true_x[3]; + out_8774680380747325588[4] = -nom_x[4] + true_x[4]; + out_8774680380747325588[5] = -nom_x[5] + true_x[5]; + out_8774680380747325588[6] = -nom_x[6] + true_x[6]; + out_8774680380747325588[7] = -nom_x[7] + true_x[7]; + out_8774680380747325588[8] = -nom_x[8] + true_x[8]; } -void H_mod_fun(double *state, double *out_8564810489090289784) { - out_8564810489090289784[0] = 1.0; - out_8564810489090289784[1] = 0.0; - out_8564810489090289784[2] = 0.0; - out_8564810489090289784[3] = 0.0; - out_8564810489090289784[4] = 0.0; - out_8564810489090289784[5] = 0.0; - out_8564810489090289784[6] = 0.0; - out_8564810489090289784[7] = 0.0; - out_8564810489090289784[8] = 0.0; - out_8564810489090289784[9] = 0.0; - out_8564810489090289784[10] = 1.0; - out_8564810489090289784[11] = 0.0; - out_8564810489090289784[12] = 0.0; - out_8564810489090289784[13] = 0.0; - out_8564810489090289784[14] = 0.0; - out_8564810489090289784[15] = 0.0; - out_8564810489090289784[16] = 0.0; - out_8564810489090289784[17] = 0.0; - out_8564810489090289784[18] = 0.0; - out_8564810489090289784[19] = 0.0; - out_8564810489090289784[20] = 1.0; - out_8564810489090289784[21] = 0.0; - out_8564810489090289784[22] = 0.0; - out_8564810489090289784[23] = 0.0; - out_8564810489090289784[24] = 0.0; - out_8564810489090289784[25] = 0.0; - out_8564810489090289784[26] = 0.0; - out_8564810489090289784[27] = 0.0; - out_8564810489090289784[28] = 0.0; - out_8564810489090289784[29] = 0.0; - out_8564810489090289784[30] = 1.0; - out_8564810489090289784[31] = 0.0; - out_8564810489090289784[32] = 0.0; - out_8564810489090289784[33] = 0.0; - out_8564810489090289784[34] = 0.0; - out_8564810489090289784[35] = 0.0; - out_8564810489090289784[36] = 0.0; - out_8564810489090289784[37] = 0.0; - out_8564810489090289784[38] = 0.0; - out_8564810489090289784[39] = 0.0; - out_8564810489090289784[40] = 1.0; - out_8564810489090289784[41] = 0.0; - out_8564810489090289784[42] = 0.0; - out_8564810489090289784[43] = 0.0; - out_8564810489090289784[44] = 0.0; - out_8564810489090289784[45] = 0.0; - out_8564810489090289784[46] = 0.0; - out_8564810489090289784[47] = 0.0; - out_8564810489090289784[48] = 0.0; - out_8564810489090289784[49] = 0.0; - out_8564810489090289784[50] = 1.0; - out_8564810489090289784[51] = 0.0; - out_8564810489090289784[52] = 0.0; - out_8564810489090289784[53] = 0.0; - out_8564810489090289784[54] = 0.0; - out_8564810489090289784[55] = 0.0; - out_8564810489090289784[56] = 0.0; - out_8564810489090289784[57] = 0.0; - out_8564810489090289784[58] = 0.0; - out_8564810489090289784[59] = 0.0; - out_8564810489090289784[60] = 1.0; - out_8564810489090289784[61] = 0.0; - out_8564810489090289784[62] = 0.0; - out_8564810489090289784[63] = 0.0; - out_8564810489090289784[64] = 0.0; - out_8564810489090289784[65] = 0.0; - out_8564810489090289784[66] = 0.0; - out_8564810489090289784[67] = 0.0; - out_8564810489090289784[68] = 0.0; - out_8564810489090289784[69] = 0.0; - out_8564810489090289784[70] = 1.0; - out_8564810489090289784[71] = 0.0; - out_8564810489090289784[72] = 0.0; - out_8564810489090289784[73] = 0.0; - out_8564810489090289784[74] = 0.0; - out_8564810489090289784[75] = 0.0; - out_8564810489090289784[76] = 0.0; - out_8564810489090289784[77] = 0.0; - out_8564810489090289784[78] = 0.0; - out_8564810489090289784[79] = 0.0; - out_8564810489090289784[80] = 1.0; +void H_mod_fun(double *state, double *out_1571472922248018296) { + out_1571472922248018296[0] = 1.0; + out_1571472922248018296[1] = 0.0; + out_1571472922248018296[2] = 0.0; + out_1571472922248018296[3] = 0.0; + out_1571472922248018296[4] = 0.0; + out_1571472922248018296[5] = 0.0; + out_1571472922248018296[6] = 0.0; + out_1571472922248018296[7] = 0.0; + out_1571472922248018296[8] = 0.0; + out_1571472922248018296[9] = 0.0; + out_1571472922248018296[10] = 1.0; + out_1571472922248018296[11] = 0.0; + out_1571472922248018296[12] = 0.0; + out_1571472922248018296[13] = 0.0; + out_1571472922248018296[14] = 0.0; + out_1571472922248018296[15] = 0.0; + out_1571472922248018296[16] = 0.0; + out_1571472922248018296[17] = 0.0; + out_1571472922248018296[18] = 0.0; + out_1571472922248018296[19] = 0.0; + out_1571472922248018296[20] = 1.0; + out_1571472922248018296[21] = 0.0; + out_1571472922248018296[22] = 0.0; + out_1571472922248018296[23] = 0.0; + out_1571472922248018296[24] = 0.0; + out_1571472922248018296[25] = 0.0; + out_1571472922248018296[26] = 0.0; + out_1571472922248018296[27] = 0.0; + out_1571472922248018296[28] = 0.0; + out_1571472922248018296[29] = 0.0; + out_1571472922248018296[30] = 1.0; + out_1571472922248018296[31] = 0.0; + out_1571472922248018296[32] = 0.0; + out_1571472922248018296[33] = 0.0; + out_1571472922248018296[34] = 0.0; + out_1571472922248018296[35] = 0.0; + out_1571472922248018296[36] = 0.0; + out_1571472922248018296[37] = 0.0; + out_1571472922248018296[38] = 0.0; + out_1571472922248018296[39] = 0.0; + out_1571472922248018296[40] = 1.0; + out_1571472922248018296[41] = 0.0; + out_1571472922248018296[42] = 0.0; + out_1571472922248018296[43] = 0.0; + out_1571472922248018296[44] = 0.0; + out_1571472922248018296[45] = 0.0; + out_1571472922248018296[46] = 0.0; + out_1571472922248018296[47] = 0.0; + out_1571472922248018296[48] = 0.0; + out_1571472922248018296[49] = 0.0; + out_1571472922248018296[50] = 1.0; + out_1571472922248018296[51] = 0.0; + out_1571472922248018296[52] = 0.0; + out_1571472922248018296[53] = 0.0; + out_1571472922248018296[54] = 0.0; + out_1571472922248018296[55] = 0.0; + out_1571472922248018296[56] = 0.0; + out_1571472922248018296[57] = 0.0; + out_1571472922248018296[58] = 0.0; + out_1571472922248018296[59] = 0.0; + out_1571472922248018296[60] = 1.0; + out_1571472922248018296[61] = 0.0; + out_1571472922248018296[62] = 0.0; + out_1571472922248018296[63] = 0.0; + out_1571472922248018296[64] = 0.0; + out_1571472922248018296[65] = 0.0; + out_1571472922248018296[66] = 0.0; + out_1571472922248018296[67] = 0.0; + out_1571472922248018296[68] = 0.0; + out_1571472922248018296[69] = 0.0; + out_1571472922248018296[70] = 1.0; + out_1571472922248018296[71] = 0.0; + out_1571472922248018296[72] = 0.0; + out_1571472922248018296[73] = 0.0; + out_1571472922248018296[74] = 0.0; + out_1571472922248018296[75] = 0.0; + out_1571472922248018296[76] = 0.0; + out_1571472922248018296[77] = 0.0; + out_1571472922248018296[78] = 0.0; + out_1571472922248018296[79] = 0.0; + out_1571472922248018296[80] = 1.0; } -void f_fun(double *state, double dt, double *out_7344896958720977953) { - out_7344896958720977953[0] = state[0]; - out_7344896958720977953[1] = state[1]; - out_7344896958720977953[2] = state[2]; - out_7344896958720977953[3] = state[3]; - out_7344896958720977953[4] = state[4]; - out_7344896958720977953[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5]; - out_7344896958720977953[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6]; - out_7344896958720977953[7] = state[7]; - out_7344896958720977953[8] = state[8]; +void f_fun(double *state, double dt, double *out_3070664500164102760) { + out_3070664500164102760[0] = state[0]; + out_3070664500164102760[1] = state[1]; + out_3070664500164102760[2] = state[2]; + out_3070664500164102760[3] = state[3]; + out_3070664500164102760[4] = state[4]; + out_3070664500164102760[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5]; + out_3070664500164102760[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6]; + out_3070664500164102760[7] = state[7]; + out_3070664500164102760[8] = state[8]; } -void F_fun(double *state, double dt, double *out_4577316669100378715) { - out_4577316669100378715[0] = 1; - out_4577316669100378715[1] = 0; - out_4577316669100378715[2] = 0; - out_4577316669100378715[3] = 0; - out_4577316669100378715[4] = 0; - out_4577316669100378715[5] = 0; - out_4577316669100378715[6] = 0; - out_4577316669100378715[7] = 0; - out_4577316669100378715[8] = 0; - out_4577316669100378715[9] = 0; - out_4577316669100378715[10] = 1; - out_4577316669100378715[11] = 0; - out_4577316669100378715[12] = 0; - out_4577316669100378715[13] = 0; - out_4577316669100378715[14] = 0; - out_4577316669100378715[15] = 0; - out_4577316669100378715[16] = 0; - out_4577316669100378715[17] = 0; - out_4577316669100378715[18] = 0; - out_4577316669100378715[19] = 0; - out_4577316669100378715[20] = 1; - out_4577316669100378715[21] = 0; - out_4577316669100378715[22] = 0; - out_4577316669100378715[23] = 0; - out_4577316669100378715[24] = 0; - out_4577316669100378715[25] = 0; - out_4577316669100378715[26] = 0; - out_4577316669100378715[27] = 0; - out_4577316669100378715[28] = 0; - out_4577316669100378715[29] = 0; - out_4577316669100378715[30] = 1; - out_4577316669100378715[31] = 0; - out_4577316669100378715[32] = 0; - out_4577316669100378715[33] = 0; - out_4577316669100378715[34] = 0; - out_4577316669100378715[35] = 0; - out_4577316669100378715[36] = 0; - out_4577316669100378715[37] = 0; - out_4577316669100378715[38] = 0; - out_4577316669100378715[39] = 0; - out_4577316669100378715[40] = 1; - out_4577316669100378715[41] = 0; - out_4577316669100378715[42] = 0; - out_4577316669100378715[43] = 0; - out_4577316669100378715[44] = 0; - out_4577316669100378715[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4])); - out_4577316669100378715[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2)); - out_4577316669100378715[47] = -dt*stiffness_front*state[0]/(mass*state[1]); - out_4577316669100378715[48] = -dt*stiffness_front*state[0]/(mass*state[1]); - out_4577316669100378715[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2))); - out_4577316669100378715[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1; - out_4577316669100378715[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4])); - out_4577316669100378715[52] = dt*stiffness_front*state[0]/(mass*state[1]); - out_4577316669100378715[53] = -9.8100000000000005*dt; - out_4577316669100378715[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4])); - out_4577316669100378715[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2)); - out_4577316669100378715[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]); - out_4577316669100378715[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]); - out_4577316669100378715[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2))); - out_4577316669100378715[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]); - out_4577316669100378715[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1; - out_4577316669100378715[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]); - out_4577316669100378715[62] = 0; - out_4577316669100378715[63] = 0; - out_4577316669100378715[64] = 0; - out_4577316669100378715[65] = 0; - out_4577316669100378715[66] = 0; - out_4577316669100378715[67] = 0; - out_4577316669100378715[68] = 0; - out_4577316669100378715[69] = 0; - out_4577316669100378715[70] = 1; - out_4577316669100378715[71] = 0; - out_4577316669100378715[72] = 0; - out_4577316669100378715[73] = 0; - out_4577316669100378715[74] = 0; - out_4577316669100378715[75] = 0; - out_4577316669100378715[76] = 0; - out_4577316669100378715[77] = 0; - out_4577316669100378715[78] = 0; - out_4577316669100378715[79] = 0; - out_4577316669100378715[80] = 1; +void F_fun(double *state, double dt, double *out_2365857006052744488) { + out_2365857006052744488[0] = 1; + out_2365857006052744488[1] = 0; + out_2365857006052744488[2] = 0; + out_2365857006052744488[3] = 0; + out_2365857006052744488[4] = 0; + out_2365857006052744488[5] = 0; + out_2365857006052744488[6] = 0; + out_2365857006052744488[7] = 0; + out_2365857006052744488[8] = 0; + out_2365857006052744488[9] = 0; + out_2365857006052744488[10] = 1; + out_2365857006052744488[11] = 0; + out_2365857006052744488[12] = 0; + out_2365857006052744488[13] = 0; + out_2365857006052744488[14] = 0; + out_2365857006052744488[15] = 0; + out_2365857006052744488[16] = 0; + out_2365857006052744488[17] = 0; + out_2365857006052744488[18] = 0; + out_2365857006052744488[19] = 0; + out_2365857006052744488[20] = 1; + out_2365857006052744488[21] = 0; + out_2365857006052744488[22] = 0; + out_2365857006052744488[23] = 0; + out_2365857006052744488[24] = 0; + out_2365857006052744488[25] = 0; + out_2365857006052744488[26] = 0; + out_2365857006052744488[27] = 0; + out_2365857006052744488[28] = 0; + out_2365857006052744488[29] = 0; + out_2365857006052744488[30] = 1; + out_2365857006052744488[31] = 0; + out_2365857006052744488[32] = 0; + out_2365857006052744488[33] = 0; + out_2365857006052744488[34] = 0; + out_2365857006052744488[35] = 0; + out_2365857006052744488[36] = 0; + out_2365857006052744488[37] = 0; + out_2365857006052744488[38] = 0; + out_2365857006052744488[39] = 0; + out_2365857006052744488[40] = 1; + out_2365857006052744488[41] = 0; + out_2365857006052744488[42] = 0; + out_2365857006052744488[43] = 0; + out_2365857006052744488[44] = 0; + out_2365857006052744488[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4])); + out_2365857006052744488[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2)); + out_2365857006052744488[47] = -dt*stiffness_front*state[0]/(mass*state[1]); + out_2365857006052744488[48] = -dt*stiffness_front*state[0]/(mass*state[1]); + out_2365857006052744488[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2))); + out_2365857006052744488[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1; + out_2365857006052744488[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4])); + out_2365857006052744488[52] = dt*stiffness_front*state[0]/(mass*state[1]); + out_2365857006052744488[53] = -9.8100000000000005*dt; + out_2365857006052744488[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4])); + out_2365857006052744488[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2)); + out_2365857006052744488[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]); + out_2365857006052744488[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]); + out_2365857006052744488[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2))); + out_2365857006052744488[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]); + out_2365857006052744488[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1; + out_2365857006052744488[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]); + out_2365857006052744488[62] = 0; + out_2365857006052744488[63] = 0; + out_2365857006052744488[64] = 0; + out_2365857006052744488[65] = 0; + out_2365857006052744488[66] = 0; + out_2365857006052744488[67] = 0; + out_2365857006052744488[68] = 0; + out_2365857006052744488[69] = 0; + out_2365857006052744488[70] = 1; + out_2365857006052744488[71] = 0; + out_2365857006052744488[72] = 0; + out_2365857006052744488[73] = 0; + out_2365857006052744488[74] = 0; + out_2365857006052744488[75] = 0; + out_2365857006052744488[76] = 0; + out_2365857006052744488[77] = 0; + out_2365857006052744488[78] = 0; + out_2365857006052744488[79] = 0; + out_2365857006052744488[80] = 1; } -void h_25(double *state, double *unused, double *out_6986192086353969465) { - out_6986192086353969465[0] = state[6]; +void h_25(double *state, double *unused, double *out_7208997417211176832) { + out_7208997417211176832[0] = state[6]; } -void H_25(double *state, double *unused, double *out_628377736821947453) { - out_628377736821947453[0] = 0; - out_628377736821947453[1] = 0; - out_628377736821947453[2] = 0; - out_628377736821947453[3] = 0; - out_628377736821947453[4] = 0; - out_628377736821947453[5] = 0; - out_628377736821947453[6] = 1; - out_628377736821947453[7] = 0; - out_628377736821947453[8] = 0; +void H_25(double *state, double *unused, double *out_3987544096248591949) { + out_3987544096248591949[0] = 0; + out_3987544096248591949[1] = 0; + out_3987544096248591949[2] = 0; + out_3987544096248591949[3] = 0; + out_3987544096248591949[4] = 0; + out_3987544096248591949[5] = 0; + out_3987544096248591949[6] = 1; + out_3987544096248591949[7] = 0; + out_3987544096248591949[8] = 0; } -void h_24(double *state, double *unused, double *out_434665502247836674) { - out_434665502247836674[0] = state[4]; - out_434665502247836674[1] = state[5]; +void h_24(double *state, double *unused, double *out_7481715524482624299) { + out_7481715524482624299[0] = state[4]; + out_7481715524482624299[1] = state[5]; } -void H_24(double *state, double *unused, double *out_2801027335827447019) { - out_2801027335827447019[0] = 0; - out_2801027335827447019[1] = 0; - out_2801027335827447019[2] = 0; - out_2801027335827447019[3] = 0; - out_2801027335827447019[4] = 1; - out_2801027335827447019[5] = 0; - out_2801027335827447019[6] = 0; - out_2801027335827447019[7] = 0; - out_2801027335827447019[8] = 0; - out_2801027335827447019[9] = 0; - out_2801027335827447019[10] = 0; - out_2801027335827447019[11] = 0; - out_2801027335827447019[12] = 0; - out_2801027335827447019[13] = 0; - out_2801027335827447019[14] = 1; - out_2801027335827447019[15] = 0; - out_2801027335827447019[16] = 0; - out_2801027335827447019[17] = 0; +void H_24(double *state, double *unused, double *out_1810329672641441976) { + out_1810329672641441976[0] = 0; + out_1810329672641441976[1] = 0; + out_1810329672641441976[2] = 0; + out_1810329672641441976[3] = 0; + out_1810329672641441976[4] = 1; + out_1810329672641441976[5] = 0; + out_1810329672641441976[6] = 0; + out_1810329672641441976[7] = 0; + out_1810329672641441976[8] = 0; + out_1810329672641441976[9] = 0; + out_1810329672641441976[10] = 0; + out_1810329672641441976[11] = 0; + out_1810329672641441976[12] = 0; + out_1810329672641441976[13] = 0; + out_1810329672641441976[14] = 1; + out_1810329672641441976[15] = 0; + out_1810329672641441976[16] = 0; + out_1810329672641441976[17] = 0; } -void h_30(double *state, double *unused, double *out_4915078315896353947) { - out_4915078315896353947[0] = state[4]; +void h_30(double *state, double *unused, double *out_438162190860825896) { + out_438162190860825896[0] = state[4]; } -void H_30(double *state, double *unused, double *out_6288312604669669302) { - out_6288312604669669302[0] = 0; - out_6288312604669669302[1] = 0; - out_6288312604669669302[2] = 0; - out_6288312604669669302[3] = 0; - out_6288312604669669302[4] = 1; - out_6288312604669669302[5] = 0; - out_6288312604669669302[6] = 0; - out_6288312604669669302[7] = 0; - out_6288312604669669302[8] = 0; +void H_30(double *state, double *unused, double *out_1469211137741343322) { + out_1469211137741343322[0] = 0; + out_1469211137741343322[1] = 0; + out_1469211137741343322[2] = 0; + out_1469211137741343322[3] = 0; + out_1469211137741343322[4] = 1; + out_1469211137741343322[5] = 0; + out_1469211137741343322[6] = 0; + out_1469211137741343322[7] = 0; + out_1469211137741343322[8] = 0; } -void h_26(double *state, double *unused, double *out_4943503076008356261) { - out_4943503076008356261[0] = state[7]; +void h_26(double *state, double *unused, double *out_4563511076800019749) { + out_4563511076800019749[0] = state[7]; } -void H_26(double *state, double *unused, double *out_4369881055696003677) { - out_4369881055696003677[0] = 0; - out_4369881055696003677[1] = 0; - out_4369881055696003677[2] = 0; - out_4369881055696003677[3] = 0; - out_4369881055696003677[4] = 0; - out_4369881055696003677[5] = 0; - out_4369881055696003677[6] = 0; - out_4369881055696003677[7] = 1; - out_4369881055696003677[8] = 0; +void H_26(double *state, double *unused, double *out_7729047415122648173) { + out_7729047415122648173[0] = 0; + out_7729047415122648173[1] = 0; + out_7729047415122648173[2] = 0; + out_7729047415122648173[3] = 0; + out_7729047415122648173[4] = 0; + out_7729047415122648173[5] = 0; + out_7729047415122648173[6] = 0; + out_7729047415122648173[7] = 1; + out_7729047415122648173[8] = 0; } -void h_27(double *state, double *unused, double *out_1984518818693123820) { - out_1984518818693123820[0] = state[3]; +void h_27(double *state, double *unused, double *out_6265487564309514397) { + out_6265487564309514397[0] = state[3]; } -void H_27(double *state, double *unused, double *out_2932479995765612434) { - out_2932479995765612434[0] = 0; - out_2932479995765612434[1] = 0; - out_2932479995765612434[2] = 0; - out_2932479995765612434[3] = 1; - out_2932479995765612434[4] = 0; - out_2932479995765612434[5] = 0; - out_2932479995765612434[6] = 0; - out_2932479995765612434[7] = 0; - out_2932479995765612434[8] = 0; +void H_27(double *state, double *unused, double *out_3643974449541768233) { + out_3643974449541768233[0] = 0; + out_3643974449541768233[1] = 0; + out_3643974449541768233[2] = 0; + out_3643974449541768233[3] = 1; + out_3643974449541768233[4] = 0; + out_3643974449541768233[5] = 0; + out_3643974449541768233[6] = 0; + out_3643974449541768233[7] = 0; + out_3643974449541768233[8] = 0; } -void h_29(double *state, double *unused, double *out_963207171662361141) { - out_963207171662361141[0] = state[1]; +void h_29(double *state, double *unused, double *out_6316447678419540984) { + out_6316447678419540984[0] = state[1]; } -void H_29(double *state, double *unused, double *out_4645842722635163467) { - out_4645842722635163467[0] = 0; - out_4645842722635163467[1] = 1; - out_4645842722635163467[2] = 0; - out_4645842722635163467[3] = 0; - out_4645842722635163467[4] = 0; - out_4645842722635163467[5] = 0; - out_4645842722635163467[6] = 0; - out_4645842722635163467[7] = 0; - out_4645842722635163467[8] = 0; +void H_29(double *state, double *unused, double *out_958979793426951138) { + out_958979793426951138[0] = 0; + out_958979793426951138[1] = 1; + out_958979793426951138[2] = 0; + out_958979793426951138[3] = 0; + out_958979793426951138[4] = 0; + out_958979793426951138[5] = 0; + out_958979793426951138[6] = 0; + out_958979793426951138[7] = 0; + out_958979793426951138[8] = 0; } -void h_28(double *state, double *unused, double *out_1002434725357825708) { - out_1002434725357825708[0] = state[0]; +void h_28(double *state, double *unused, double *out_3384947045134040079) { + out_3384947045134040079[0] = state[0]; } -void H_28(double *state, double *unused, double *out_2682212451069837216) { - out_2682212451069837216[0] = 1; - out_2682212451069837216[1] = 0; - out_2682212451069837216[2] = 0; - out_2682212451069837216[3] = 0; - out_2682212451069837216[4] = 0; - out_2682212451069837216[5] = 0; - out_2682212451069837216[6] = 0; - out_2682212451069837216[7] = 0; - out_2682212451069837216[8] = 0; +void H_28(double *state, double *unused, double *out_6041378810496481712) { + out_6041378810496481712[0] = 1; + out_6041378810496481712[1] = 0; + out_6041378810496481712[2] = 0; + out_6041378810496481712[3] = 0; + out_6041378810496481712[4] = 0; + out_6041378810496481712[5] = 0; + out_6041378810496481712[6] = 0; + out_6041378810496481712[7] = 0; + out_6041378810496481712[8] = 0; } -void h_31(double *state, double *unused, double *out_7261386148638475354) { - out_7261386148638475354[0] = state[8]; +void h_31(double *state, double *unused, double *out_2597869179779832900) { + out_2597869179779832900[0] = state[8]; } -void H_31(double *state, double *unused, double *out_597731774944987025) { - out_597731774944987025[0] = 0; - out_597731774944987025[1] = 0; - out_597731774944987025[2] = 0; - out_597731774944987025[3] = 0; - out_597731774944987025[4] = 0; - out_597731774944987025[5] = 0; - out_597731774944987025[6] = 0; - out_597731774944987025[7] = 0; - out_597731774944987025[8] = 1; +void H_31(double *state, double *unused, double *out_8355255517355999649) { + out_8355255517355999649[0] = 0; + out_8355255517355999649[1] = 0; + out_8355255517355999649[2] = 0; + out_8355255517355999649[3] = 0; + out_8355255517355999649[4] = 0; + out_8355255517355999649[5] = 0; + out_8355255517355999649[6] = 0; + out_8355255517355999649[7] = 0; + out_8355255517355999649[8] = 1; } #include #include @@ -518,68 +518,68 @@ void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, doubl void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) { update<1, 3, 0>(in_x, in_P, h_31, H_31, NULL, in_z, in_R, in_ea, MAHA_THRESH_31); } -void car_err_fun(double *nom_x, double *delta_x, double *out_5406094264205448922) { - err_fun(nom_x, delta_x, out_5406094264205448922); +void car_err_fun(double *nom_x, double *delta_x, double *out_1976458697034392713) { + err_fun(nom_x, delta_x, out_1976458697034392713); } -void car_inv_err_fun(double *nom_x, double *true_x, double *out_7302786751934147898) { - inv_err_fun(nom_x, true_x, out_7302786751934147898); +void car_inv_err_fun(double *nom_x, double *true_x, double *out_8774680380747325588) { + inv_err_fun(nom_x, true_x, out_8774680380747325588); } -void car_H_mod_fun(double *state, double *out_8564810489090289784) { - H_mod_fun(state, out_8564810489090289784); +void car_H_mod_fun(double *state, double *out_1571472922248018296) { + H_mod_fun(state, out_1571472922248018296); } -void car_f_fun(double *state, double dt, double *out_7344896958720977953) { - f_fun(state, dt, out_7344896958720977953); +void car_f_fun(double *state, double dt, double *out_3070664500164102760) { + f_fun(state, dt, out_3070664500164102760); } -void car_F_fun(double *state, double dt, double *out_4577316669100378715) { - F_fun(state, dt, out_4577316669100378715); +void car_F_fun(double *state, double dt, double *out_2365857006052744488) { + F_fun(state, dt, out_2365857006052744488); } -void car_h_25(double *state, double *unused, double *out_6986192086353969465) { - h_25(state, unused, out_6986192086353969465); +void car_h_25(double *state, double *unused, double *out_7208997417211176832) { + h_25(state, unused, out_7208997417211176832); } -void car_H_25(double *state, double *unused, double *out_628377736821947453) { - H_25(state, unused, out_628377736821947453); +void car_H_25(double *state, double *unused, double *out_3987544096248591949) { + H_25(state, unused, out_3987544096248591949); } -void car_h_24(double *state, double *unused, double *out_434665502247836674) { - h_24(state, unused, out_434665502247836674); +void car_h_24(double *state, double *unused, double *out_7481715524482624299) { + h_24(state, unused, out_7481715524482624299); } -void car_H_24(double *state, double *unused, double *out_2801027335827447019) { - H_24(state, unused, out_2801027335827447019); +void car_H_24(double *state, double *unused, double *out_1810329672641441976) { + H_24(state, unused, out_1810329672641441976); } -void car_h_30(double *state, double *unused, double *out_4915078315896353947) { - h_30(state, unused, out_4915078315896353947); +void car_h_30(double *state, double *unused, double *out_438162190860825896) { + h_30(state, unused, out_438162190860825896); } -void car_H_30(double *state, double *unused, double *out_6288312604669669302) { - H_30(state, unused, out_6288312604669669302); +void car_H_30(double *state, double *unused, double *out_1469211137741343322) { + H_30(state, unused, out_1469211137741343322); } -void car_h_26(double *state, double *unused, double *out_4943503076008356261) { - h_26(state, unused, out_4943503076008356261); +void car_h_26(double *state, double *unused, double *out_4563511076800019749) { + h_26(state, unused, out_4563511076800019749); } -void car_H_26(double *state, double *unused, double *out_4369881055696003677) { - H_26(state, unused, out_4369881055696003677); +void car_H_26(double *state, double *unused, double *out_7729047415122648173) { + H_26(state, unused, out_7729047415122648173); } -void car_h_27(double *state, double *unused, double *out_1984518818693123820) { - h_27(state, unused, out_1984518818693123820); +void car_h_27(double *state, double *unused, double *out_6265487564309514397) { + h_27(state, unused, out_6265487564309514397); } -void car_H_27(double *state, double *unused, double *out_2932479995765612434) { - H_27(state, unused, out_2932479995765612434); +void car_H_27(double *state, double *unused, double *out_3643974449541768233) { + H_27(state, unused, out_3643974449541768233); } -void car_h_29(double *state, double *unused, double *out_963207171662361141) { - h_29(state, unused, out_963207171662361141); +void car_h_29(double *state, double *unused, double *out_6316447678419540984) { + h_29(state, unused, out_6316447678419540984); } -void car_H_29(double *state, double *unused, double *out_4645842722635163467) { - H_29(state, unused, out_4645842722635163467); +void car_H_29(double *state, double *unused, double *out_958979793426951138) { + H_29(state, unused, out_958979793426951138); } -void car_h_28(double *state, double *unused, double *out_1002434725357825708) { - h_28(state, unused, out_1002434725357825708); +void car_h_28(double *state, double *unused, double *out_3384947045134040079) { + h_28(state, unused, out_3384947045134040079); } -void car_H_28(double *state, double *unused, double *out_2682212451069837216) { - H_28(state, unused, out_2682212451069837216); +void car_H_28(double *state, double *unused, double *out_6041378810496481712) { + H_28(state, unused, out_6041378810496481712); } -void car_h_31(double *state, double *unused, double *out_7261386148638475354) { - h_31(state, unused, out_7261386148638475354); +void car_h_31(double *state, double *unused, double *out_2597869179779832900) { + h_31(state, unused, out_2597869179779832900); } -void car_H_31(double *state, double *unused, double *out_597731774944987025) { - H_31(state, unused, out_597731774944987025); +void car_H_31(double *state, double *unused, double *out_8355255517355999649) { + H_31(state, unused, out_8355255517355999649); } void car_predict(double *in_x, double *in_P, double *in_Q, double dt) { predict(in_x, in_P, in_Q, dt); diff --git a/selfdrive/locationd/models/generated/car.h b/selfdrive/locationd/models/generated/car.h index f8813fec3..6b7db4049 100644 --- a/selfdrive/locationd/models/generated/car.h +++ b/selfdrive/locationd/models/generated/car.h @@ -9,27 +9,27 @@ void car_update_27(double *in_x, double *in_P, double *in_z, double *in_R, doubl void car_update_29(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea); void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea); void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea); -void car_err_fun(double *nom_x, double *delta_x, double *out_5406094264205448922); -void car_inv_err_fun(double *nom_x, double *true_x, double *out_7302786751934147898); -void car_H_mod_fun(double *state, double *out_8564810489090289784); -void car_f_fun(double *state, double dt, double *out_7344896958720977953); -void car_F_fun(double *state, double dt, double *out_4577316669100378715); -void car_h_25(double *state, double *unused, double *out_6986192086353969465); -void car_H_25(double *state, double *unused, double *out_628377736821947453); -void car_h_24(double *state, double *unused, double *out_434665502247836674); -void car_H_24(double *state, double *unused, double *out_2801027335827447019); -void car_h_30(double *state, double *unused, double *out_4915078315896353947); -void car_H_30(double *state, double *unused, double *out_6288312604669669302); -void car_h_26(double *state, double *unused, double *out_4943503076008356261); -void car_H_26(double *state, double *unused, double *out_4369881055696003677); -void car_h_27(double *state, double *unused, double *out_1984518818693123820); -void car_H_27(double *state, double *unused, double *out_2932479995765612434); -void car_h_29(double *state, double *unused, double *out_963207171662361141); -void car_H_29(double *state, double *unused, double *out_4645842722635163467); -void car_h_28(double *state, double *unused, double *out_1002434725357825708); -void car_H_28(double *state, double *unused, double *out_2682212451069837216); -void car_h_31(double *state, double *unused, double *out_7261386148638475354); -void car_H_31(double *state, double *unused, double *out_597731774944987025); +void car_err_fun(double *nom_x, double *delta_x, double *out_1976458697034392713); +void car_inv_err_fun(double *nom_x, double *true_x, double *out_8774680380747325588); +void car_H_mod_fun(double *state, double *out_1571472922248018296); +void car_f_fun(double *state, double dt, double *out_3070664500164102760); +void car_F_fun(double *state, double dt, double *out_2365857006052744488); +void car_h_25(double *state, double *unused, double *out_7208997417211176832); +void car_H_25(double *state, double *unused, double *out_3987544096248591949); +void car_h_24(double *state, double *unused, double *out_7481715524482624299); +void car_H_24(double *state, double *unused, double *out_1810329672641441976); +void car_h_30(double *state, double *unused, double *out_438162190860825896); +void car_H_30(double *state, double *unused, double *out_1469211137741343322); +void car_h_26(double *state, double *unused, double *out_4563511076800019749); +void car_H_26(double *state, double *unused, double *out_7729047415122648173); +void car_h_27(double *state, double *unused, double *out_6265487564309514397); +void car_H_27(double *state, double *unused, double *out_3643974449541768233); +void car_h_29(double *state, double *unused, double *out_6316447678419540984); +void car_H_29(double *state, double *unused, double *out_958979793426951138); +void car_h_28(double *state, double *unused, double *out_3384947045134040079); +void car_H_28(double *state, double *unused, double *out_6041378810496481712); +void car_h_31(double *state, double *unused, double *out_2597869179779832900); +void car_H_31(double *state, double *unused, double *out_8355255517355999649); void car_predict(double *in_x, double *in_P, double *in_Q, double dt); void car_set_mass(double x); void car_set_rotational_inertia(double x); diff --git a/selfdrive/locationd/models/generated/pose.cpp b/selfdrive/locationd/models/generated/pose.cpp index 2ef680f47..7134d9104 100644 --- a/selfdrive/locationd/models/generated/pose.cpp +++ b/selfdrive/locationd/models/generated/pose.cpp @@ -17,961 +17,961 @@ const static double MAHA_THRESH_14 = 7.814727903251177; * * * This file is part of 'ekf' * ******************************************************************************/ -void err_fun(double *nom_x, double *delta_x, double *out_6497612872484174174) { - out_6497612872484174174[0] = delta_x[0] + nom_x[0]; - out_6497612872484174174[1] = delta_x[1] + nom_x[1]; - out_6497612872484174174[2] = delta_x[2] + nom_x[2]; - out_6497612872484174174[3] = delta_x[3] + nom_x[3]; - out_6497612872484174174[4] = delta_x[4] + nom_x[4]; - out_6497612872484174174[5] = delta_x[5] + nom_x[5]; - out_6497612872484174174[6] = delta_x[6] + nom_x[6]; - out_6497612872484174174[7] = delta_x[7] + nom_x[7]; - out_6497612872484174174[8] = delta_x[8] + nom_x[8]; - out_6497612872484174174[9] = delta_x[9] + nom_x[9]; - out_6497612872484174174[10] = delta_x[10] + nom_x[10]; - out_6497612872484174174[11] = delta_x[11] + nom_x[11]; - out_6497612872484174174[12] = delta_x[12] + nom_x[12]; - out_6497612872484174174[13] = delta_x[13] + nom_x[13]; - out_6497612872484174174[14] = delta_x[14] + nom_x[14]; - out_6497612872484174174[15] = delta_x[15] + nom_x[15]; - out_6497612872484174174[16] = delta_x[16] + nom_x[16]; - out_6497612872484174174[17] = delta_x[17] + nom_x[17]; +void err_fun(double *nom_x, double *delta_x, double *out_812796242528121648) { + out_812796242528121648[0] = delta_x[0] + nom_x[0]; + out_812796242528121648[1] = delta_x[1] + nom_x[1]; + out_812796242528121648[2] = delta_x[2] + nom_x[2]; + out_812796242528121648[3] = delta_x[3] + nom_x[3]; + out_812796242528121648[4] = delta_x[4] + nom_x[4]; + out_812796242528121648[5] = delta_x[5] + nom_x[5]; + out_812796242528121648[6] = delta_x[6] + nom_x[6]; + out_812796242528121648[7] = delta_x[7] + nom_x[7]; + out_812796242528121648[8] = delta_x[8] + nom_x[8]; + out_812796242528121648[9] = delta_x[9] + nom_x[9]; + out_812796242528121648[10] = delta_x[10] + nom_x[10]; + out_812796242528121648[11] = delta_x[11] + nom_x[11]; + out_812796242528121648[12] = delta_x[12] + nom_x[12]; + out_812796242528121648[13] = delta_x[13] + nom_x[13]; + out_812796242528121648[14] = delta_x[14] + nom_x[14]; + out_812796242528121648[15] = delta_x[15] + nom_x[15]; + out_812796242528121648[16] = delta_x[16] + nom_x[16]; + out_812796242528121648[17] = delta_x[17] + nom_x[17]; } -void inv_err_fun(double *nom_x, double *true_x, double *out_1975580934350294204) { - out_1975580934350294204[0] = -nom_x[0] + true_x[0]; - out_1975580934350294204[1] = -nom_x[1] + true_x[1]; - out_1975580934350294204[2] = -nom_x[2] + true_x[2]; - out_1975580934350294204[3] = -nom_x[3] + true_x[3]; - out_1975580934350294204[4] = -nom_x[4] + true_x[4]; - out_1975580934350294204[5] = -nom_x[5] + true_x[5]; - out_1975580934350294204[6] = -nom_x[6] + true_x[6]; - out_1975580934350294204[7] = -nom_x[7] + true_x[7]; - out_1975580934350294204[8] = -nom_x[8] + true_x[8]; - out_1975580934350294204[9] = -nom_x[9] + true_x[9]; - out_1975580934350294204[10] = -nom_x[10] + true_x[10]; - out_1975580934350294204[11] = -nom_x[11] + true_x[11]; - out_1975580934350294204[12] = -nom_x[12] + true_x[12]; - out_1975580934350294204[13] = -nom_x[13] + true_x[13]; - out_1975580934350294204[14] = -nom_x[14] + true_x[14]; - out_1975580934350294204[15] = -nom_x[15] + true_x[15]; - out_1975580934350294204[16] = -nom_x[16] + true_x[16]; - out_1975580934350294204[17] = -nom_x[17] + true_x[17]; +void inv_err_fun(double *nom_x, double *true_x, double *out_2630998712382937796) { + out_2630998712382937796[0] = -nom_x[0] + true_x[0]; + out_2630998712382937796[1] = -nom_x[1] + true_x[1]; + out_2630998712382937796[2] = -nom_x[2] + true_x[2]; + out_2630998712382937796[3] = -nom_x[3] + true_x[3]; + out_2630998712382937796[4] = -nom_x[4] + true_x[4]; + out_2630998712382937796[5] = -nom_x[5] + true_x[5]; + out_2630998712382937796[6] = -nom_x[6] + true_x[6]; + out_2630998712382937796[7] = -nom_x[7] + true_x[7]; + out_2630998712382937796[8] = -nom_x[8] + true_x[8]; + out_2630998712382937796[9] = -nom_x[9] + true_x[9]; + out_2630998712382937796[10] = -nom_x[10] + true_x[10]; + out_2630998712382937796[11] = -nom_x[11] + true_x[11]; + out_2630998712382937796[12] = -nom_x[12] + true_x[12]; + out_2630998712382937796[13] = -nom_x[13] + true_x[13]; + out_2630998712382937796[14] = -nom_x[14] + true_x[14]; + out_2630998712382937796[15] = -nom_x[15] + true_x[15]; + out_2630998712382937796[16] = -nom_x[16] + true_x[16]; + out_2630998712382937796[17] = -nom_x[17] + true_x[17]; } -void H_mod_fun(double *state, double *out_4617418789543565628) { - out_4617418789543565628[0] = 1.0; - out_4617418789543565628[1] = 0.0; - out_4617418789543565628[2] = 0.0; - out_4617418789543565628[3] = 0.0; - out_4617418789543565628[4] = 0.0; - out_4617418789543565628[5] = 0.0; - out_4617418789543565628[6] = 0.0; - out_4617418789543565628[7] = 0.0; - out_4617418789543565628[8] = 0.0; - out_4617418789543565628[9] = 0.0; - out_4617418789543565628[10] = 0.0; - out_4617418789543565628[11] = 0.0; - out_4617418789543565628[12] = 0.0; - out_4617418789543565628[13] = 0.0; - out_4617418789543565628[14] = 0.0; - out_4617418789543565628[15] = 0.0; - out_4617418789543565628[16] = 0.0; - out_4617418789543565628[17] = 0.0; - out_4617418789543565628[18] = 0.0; - out_4617418789543565628[19] = 1.0; - out_4617418789543565628[20] = 0.0; - out_4617418789543565628[21] = 0.0; - out_4617418789543565628[22] = 0.0; - out_4617418789543565628[23] = 0.0; - out_4617418789543565628[24] = 0.0; - out_4617418789543565628[25] = 0.0; - out_4617418789543565628[26] = 0.0; - out_4617418789543565628[27] = 0.0; - out_4617418789543565628[28] = 0.0; - out_4617418789543565628[29] = 0.0; - out_4617418789543565628[30] = 0.0; - out_4617418789543565628[31] = 0.0; - out_4617418789543565628[32] = 0.0; - out_4617418789543565628[33] = 0.0; - out_4617418789543565628[34] = 0.0; - out_4617418789543565628[35] = 0.0; - out_4617418789543565628[36] = 0.0; - out_4617418789543565628[37] = 0.0; - out_4617418789543565628[38] = 1.0; - out_4617418789543565628[39] = 0.0; - out_4617418789543565628[40] = 0.0; - out_4617418789543565628[41] = 0.0; - out_4617418789543565628[42] = 0.0; - out_4617418789543565628[43] = 0.0; - out_4617418789543565628[44] = 0.0; - out_4617418789543565628[45] = 0.0; - out_4617418789543565628[46] = 0.0; - out_4617418789543565628[47] = 0.0; - out_4617418789543565628[48] = 0.0; - out_4617418789543565628[49] = 0.0; - out_4617418789543565628[50] = 0.0; - out_4617418789543565628[51] = 0.0; - out_4617418789543565628[52] = 0.0; - out_4617418789543565628[53] = 0.0; - out_4617418789543565628[54] = 0.0; - out_4617418789543565628[55] = 0.0; - out_4617418789543565628[56] = 0.0; - out_4617418789543565628[57] = 1.0; - out_4617418789543565628[58] = 0.0; - out_4617418789543565628[59] = 0.0; - out_4617418789543565628[60] = 0.0; - out_4617418789543565628[61] = 0.0; - out_4617418789543565628[62] = 0.0; - out_4617418789543565628[63] = 0.0; - out_4617418789543565628[64] = 0.0; - out_4617418789543565628[65] = 0.0; - out_4617418789543565628[66] = 0.0; - out_4617418789543565628[67] = 0.0; - out_4617418789543565628[68] = 0.0; - out_4617418789543565628[69] = 0.0; - out_4617418789543565628[70] = 0.0; - out_4617418789543565628[71] = 0.0; - out_4617418789543565628[72] = 0.0; - out_4617418789543565628[73] = 0.0; - out_4617418789543565628[74] = 0.0; - out_4617418789543565628[75] = 0.0; - out_4617418789543565628[76] = 1.0; - out_4617418789543565628[77] = 0.0; - out_4617418789543565628[78] = 0.0; - out_4617418789543565628[79] = 0.0; - out_4617418789543565628[80] = 0.0; - out_4617418789543565628[81] = 0.0; - out_4617418789543565628[82] = 0.0; - out_4617418789543565628[83] = 0.0; - out_4617418789543565628[84] = 0.0; - out_4617418789543565628[85] = 0.0; - out_4617418789543565628[86] = 0.0; - out_4617418789543565628[87] = 0.0; - out_4617418789543565628[88] = 0.0; - out_4617418789543565628[89] = 0.0; - out_4617418789543565628[90] = 0.0; - out_4617418789543565628[91] = 0.0; - out_4617418789543565628[92] = 0.0; - out_4617418789543565628[93] = 0.0; - out_4617418789543565628[94] = 0.0; - out_4617418789543565628[95] = 1.0; - out_4617418789543565628[96] = 0.0; - out_4617418789543565628[97] = 0.0; - out_4617418789543565628[98] = 0.0; - out_4617418789543565628[99] = 0.0; - out_4617418789543565628[100] = 0.0; - out_4617418789543565628[101] = 0.0; - out_4617418789543565628[102] = 0.0; - out_4617418789543565628[103] = 0.0; - out_4617418789543565628[104] = 0.0; - out_4617418789543565628[105] = 0.0; - out_4617418789543565628[106] = 0.0; - out_4617418789543565628[107] = 0.0; - out_4617418789543565628[108] = 0.0; - out_4617418789543565628[109] = 0.0; - out_4617418789543565628[110] = 0.0; - out_4617418789543565628[111] = 0.0; - out_4617418789543565628[112] = 0.0; - out_4617418789543565628[113] = 0.0; - out_4617418789543565628[114] = 1.0; - out_4617418789543565628[115] = 0.0; - out_4617418789543565628[116] = 0.0; - out_4617418789543565628[117] = 0.0; - out_4617418789543565628[118] = 0.0; - out_4617418789543565628[119] = 0.0; - out_4617418789543565628[120] = 0.0; - out_4617418789543565628[121] = 0.0; - out_4617418789543565628[122] = 0.0; - out_4617418789543565628[123] = 0.0; - out_4617418789543565628[124] = 0.0; - out_4617418789543565628[125] = 0.0; - out_4617418789543565628[126] = 0.0; - out_4617418789543565628[127] = 0.0; - out_4617418789543565628[128] = 0.0; - out_4617418789543565628[129] = 0.0; - out_4617418789543565628[130] = 0.0; - out_4617418789543565628[131] = 0.0; - out_4617418789543565628[132] = 0.0; - out_4617418789543565628[133] = 1.0; - out_4617418789543565628[134] = 0.0; - out_4617418789543565628[135] = 0.0; - out_4617418789543565628[136] = 0.0; - out_4617418789543565628[137] = 0.0; - out_4617418789543565628[138] = 0.0; - out_4617418789543565628[139] = 0.0; - out_4617418789543565628[140] = 0.0; - out_4617418789543565628[141] = 0.0; - out_4617418789543565628[142] = 0.0; - out_4617418789543565628[143] = 0.0; - out_4617418789543565628[144] = 0.0; - out_4617418789543565628[145] = 0.0; - out_4617418789543565628[146] = 0.0; - out_4617418789543565628[147] = 0.0; - out_4617418789543565628[148] = 0.0; - out_4617418789543565628[149] = 0.0; - out_4617418789543565628[150] = 0.0; - out_4617418789543565628[151] = 0.0; - out_4617418789543565628[152] = 1.0; - out_4617418789543565628[153] = 0.0; - out_4617418789543565628[154] = 0.0; - out_4617418789543565628[155] = 0.0; - out_4617418789543565628[156] = 0.0; - out_4617418789543565628[157] = 0.0; - out_4617418789543565628[158] = 0.0; - out_4617418789543565628[159] = 0.0; - out_4617418789543565628[160] = 0.0; - out_4617418789543565628[161] = 0.0; - out_4617418789543565628[162] = 0.0; - out_4617418789543565628[163] = 0.0; - out_4617418789543565628[164] = 0.0; - out_4617418789543565628[165] = 0.0; - out_4617418789543565628[166] = 0.0; - out_4617418789543565628[167] = 0.0; - out_4617418789543565628[168] = 0.0; - out_4617418789543565628[169] = 0.0; - out_4617418789543565628[170] = 0.0; - out_4617418789543565628[171] = 1.0; - out_4617418789543565628[172] = 0.0; - out_4617418789543565628[173] = 0.0; - out_4617418789543565628[174] = 0.0; - out_4617418789543565628[175] = 0.0; - out_4617418789543565628[176] = 0.0; - out_4617418789543565628[177] = 0.0; - out_4617418789543565628[178] = 0.0; - out_4617418789543565628[179] = 0.0; - out_4617418789543565628[180] = 0.0; - out_4617418789543565628[181] = 0.0; - out_4617418789543565628[182] = 0.0; - out_4617418789543565628[183] = 0.0; - out_4617418789543565628[184] = 0.0; - out_4617418789543565628[185] = 0.0; - out_4617418789543565628[186] = 0.0; - out_4617418789543565628[187] = 0.0; - out_4617418789543565628[188] = 0.0; - out_4617418789543565628[189] = 0.0; - out_4617418789543565628[190] = 1.0; - out_4617418789543565628[191] = 0.0; - out_4617418789543565628[192] = 0.0; - out_4617418789543565628[193] = 0.0; - out_4617418789543565628[194] = 0.0; - out_4617418789543565628[195] = 0.0; - out_4617418789543565628[196] = 0.0; - out_4617418789543565628[197] = 0.0; - out_4617418789543565628[198] = 0.0; - out_4617418789543565628[199] = 0.0; - out_4617418789543565628[200] = 0.0; - out_4617418789543565628[201] = 0.0; - out_4617418789543565628[202] = 0.0; - out_4617418789543565628[203] = 0.0; - out_4617418789543565628[204] = 0.0; - out_4617418789543565628[205] = 0.0; - out_4617418789543565628[206] = 0.0; - out_4617418789543565628[207] = 0.0; - out_4617418789543565628[208] = 0.0; - out_4617418789543565628[209] = 1.0; - out_4617418789543565628[210] = 0.0; - out_4617418789543565628[211] = 0.0; - out_4617418789543565628[212] = 0.0; - out_4617418789543565628[213] = 0.0; - out_4617418789543565628[214] = 0.0; - out_4617418789543565628[215] = 0.0; - out_4617418789543565628[216] = 0.0; - out_4617418789543565628[217] = 0.0; - out_4617418789543565628[218] = 0.0; - out_4617418789543565628[219] = 0.0; - out_4617418789543565628[220] = 0.0; - out_4617418789543565628[221] = 0.0; - out_4617418789543565628[222] = 0.0; - out_4617418789543565628[223] = 0.0; - out_4617418789543565628[224] = 0.0; - out_4617418789543565628[225] = 0.0; - out_4617418789543565628[226] = 0.0; - out_4617418789543565628[227] = 0.0; - out_4617418789543565628[228] = 1.0; - out_4617418789543565628[229] = 0.0; - out_4617418789543565628[230] = 0.0; - out_4617418789543565628[231] = 0.0; - out_4617418789543565628[232] = 0.0; - out_4617418789543565628[233] = 0.0; - out_4617418789543565628[234] = 0.0; - out_4617418789543565628[235] = 0.0; - out_4617418789543565628[236] = 0.0; - out_4617418789543565628[237] = 0.0; - out_4617418789543565628[238] = 0.0; - out_4617418789543565628[239] = 0.0; - out_4617418789543565628[240] = 0.0; - out_4617418789543565628[241] = 0.0; - out_4617418789543565628[242] = 0.0; - out_4617418789543565628[243] = 0.0; - out_4617418789543565628[244] = 0.0; - out_4617418789543565628[245] = 0.0; - out_4617418789543565628[246] = 0.0; - out_4617418789543565628[247] = 1.0; - out_4617418789543565628[248] = 0.0; - out_4617418789543565628[249] = 0.0; - out_4617418789543565628[250] = 0.0; - out_4617418789543565628[251] = 0.0; - out_4617418789543565628[252] = 0.0; - out_4617418789543565628[253] = 0.0; - out_4617418789543565628[254] = 0.0; - out_4617418789543565628[255] = 0.0; - out_4617418789543565628[256] = 0.0; - out_4617418789543565628[257] = 0.0; - out_4617418789543565628[258] = 0.0; - out_4617418789543565628[259] = 0.0; - out_4617418789543565628[260] = 0.0; - out_4617418789543565628[261] = 0.0; - out_4617418789543565628[262] = 0.0; - out_4617418789543565628[263] = 0.0; - out_4617418789543565628[264] = 0.0; - out_4617418789543565628[265] = 0.0; - out_4617418789543565628[266] = 1.0; - out_4617418789543565628[267] = 0.0; - out_4617418789543565628[268] = 0.0; - out_4617418789543565628[269] = 0.0; - out_4617418789543565628[270] = 0.0; - out_4617418789543565628[271] = 0.0; - out_4617418789543565628[272] = 0.0; - out_4617418789543565628[273] = 0.0; - out_4617418789543565628[274] = 0.0; - out_4617418789543565628[275] = 0.0; - out_4617418789543565628[276] = 0.0; - out_4617418789543565628[277] = 0.0; - out_4617418789543565628[278] = 0.0; - out_4617418789543565628[279] = 0.0; - out_4617418789543565628[280] = 0.0; - out_4617418789543565628[281] = 0.0; - out_4617418789543565628[282] = 0.0; - out_4617418789543565628[283] = 0.0; - out_4617418789543565628[284] = 0.0; - out_4617418789543565628[285] = 1.0; - out_4617418789543565628[286] = 0.0; - out_4617418789543565628[287] = 0.0; - out_4617418789543565628[288] = 0.0; - out_4617418789543565628[289] = 0.0; - out_4617418789543565628[290] = 0.0; - out_4617418789543565628[291] = 0.0; - out_4617418789543565628[292] = 0.0; - out_4617418789543565628[293] = 0.0; - out_4617418789543565628[294] = 0.0; - out_4617418789543565628[295] = 0.0; - out_4617418789543565628[296] = 0.0; - out_4617418789543565628[297] = 0.0; - out_4617418789543565628[298] = 0.0; - out_4617418789543565628[299] = 0.0; - out_4617418789543565628[300] = 0.0; - out_4617418789543565628[301] = 0.0; - out_4617418789543565628[302] = 0.0; - out_4617418789543565628[303] = 0.0; - out_4617418789543565628[304] = 1.0; - out_4617418789543565628[305] = 0.0; - out_4617418789543565628[306] = 0.0; - out_4617418789543565628[307] = 0.0; - out_4617418789543565628[308] = 0.0; - out_4617418789543565628[309] = 0.0; - out_4617418789543565628[310] = 0.0; - out_4617418789543565628[311] = 0.0; - out_4617418789543565628[312] = 0.0; - out_4617418789543565628[313] = 0.0; - out_4617418789543565628[314] = 0.0; - out_4617418789543565628[315] = 0.0; - out_4617418789543565628[316] = 0.0; - out_4617418789543565628[317] = 0.0; - out_4617418789543565628[318] = 0.0; - out_4617418789543565628[319] = 0.0; - out_4617418789543565628[320] = 0.0; - out_4617418789543565628[321] = 0.0; - out_4617418789543565628[322] = 0.0; - out_4617418789543565628[323] = 1.0; +void H_mod_fun(double *state, double *out_8952125250503643232) { + out_8952125250503643232[0] = 1.0; + out_8952125250503643232[1] = 0.0; + out_8952125250503643232[2] = 0.0; + out_8952125250503643232[3] = 0.0; + out_8952125250503643232[4] = 0.0; + out_8952125250503643232[5] = 0.0; + out_8952125250503643232[6] = 0.0; + out_8952125250503643232[7] = 0.0; + out_8952125250503643232[8] = 0.0; + out_8952125250503643232[9] = 0.0; + out_8952125250503643232[10] = 0.0; + out_8952125250503643232[11] = 0.0; + out_8952125250503643232[12] = 0.0; + out_8952125250503643232[13] = 0.0; + out_8952125250503643232[14] = 0.0; + out_8952125250503643232[15] = 0.0; + out_8952125250503643232[16] = 0.0; + out_8952125250503643232[17] = 0.0; + out_8952125250503643232[18] = 0.0; + out_8952125250503643232[19] = 1.0; + out_8952125250503643232[20] = 0.0; + out_8952125250503643232[21] = 0.0; + out_8952125250503643232[22] = 0.0; + out_8952125250503643232[23] = 0.0; + out_8952125250503643232[24] = 0.0; + out_8952125250503643232[25] = 0.0; + out_8952125250503643232[26] = 0.0; + out_8952125250503643232[27] = 0.0; + out_8952125250503643232[28] = 0.0; + out_8952125250503643232[29] = 0.0; + out_8952125250503643232[30] = 0.0; + out_8952125250503643232[31] = 0.0; + out_8952125250503643232[32] = 0.0; + out_8952125250503643232[33] = 0.0; + out_8952125250503643232[34] = 0.0; + out_8952125250503643232[35] = 0.0; + out_8952125250503643232[36] = 0.0; + out_8952125250503643232[37] = 0.0; + out_8952125250503643232[38] = 1.0; + out_8952125250503643232[39] = 0.0; + out_8952125250503643232[40] = 0.0; + out_8952125250503643232[41] = 0.0; + out_8952125250503643232[42] = 0.0; + out_8952125250503643232[43] = 0.0; + out_8952125250503643232[44] = 0.0; + out_8952125250503643232[45] = 0.0; + out_8952125250503643232[46] = 0.0; + out_8952125250503643232[47] = 0.0; + out_8952125250503643232[48] = 0.0; + out_8952125250503643232[49] = 0.0; + out_8952125250503643232[50] = 0.0; + out_8952125250503643232[51] = 0.0; + out_8952125250503643232[52] = 0.0; + out_8952125250503643232[53] = 0.0; + out_8952125250503643232[54] = 0.0; + out_8952125250503643232[55] = 0.0; + out_8952125250503643232[56] = 0.0; + out_8952125250503643232[57] = 1.0; + out_8952125250503643232[58] = 0.0; + out_8952125250503643232[59] = 0.0; + out_8952125250503643232[60] = 0.0; + out_8952125250503643232[61] = 0.0; + out_8952125250503643232[62] = 0.0; + out_8952125250503643232[63] = 0.0; + out_8952125250503643232[64] = 0.0; + out_8952125250503643232[65] = 0.0; + out_8952125250503643232[66] = 0.0; + out_8952125250503643232[67] = 0.0; + out_8952125250503643232[68] = 0.0; + out_8952125250503643232[69] = 0.0; + out_8952125250503643232[70] = 0.0; + out_8952125250503643232[71] = 0.0; + out_8952125250503643232[72] = 0.0; + out_8952125250503643232[73] = 0.0; + out_8952125250503643232[74] = 0.0; + out_8952125250503643232[75] = 0.0; + out_8952125250503643232[76] = 1.0; + out_8952125250503643232[77] = 0.0; + out_8952125250503643232[78] = 0.0; + out_8952125250503643232[79] = 0.0; + out_8952125250503643232[80] = 0.0; + out_8952125250503643232[81] = 0.0; + out_8952125250503643232[82] = 0.0; + out_8952125250503643232[83] = 0.0; + out_8952125250503643232[84] = 0.0; + out_8952125250503643232[85] = 0.0; + out_8952125250503643232[86] = 0.0; + out_8952125250503643232[87] = 0.0; + out_8952125250503643232[88] = 0.0; + out_8952125250503643232[89] = 0.0; + out_8952125250503643232[90] = 0.0; + out_8952125250503643232[91] = 0.0; + out_8952125250503643232[92] = 0.0; + out_8952125250503643232[93] = 0.0; + out_8952125250503643232[94] = 0.0; + out_8952125250503643232[95] = 1.0; + out_8952125250503643232[96] = 0.0; + out_8952125250503643232[97] = 0.0; + out_8952125250503643232[98] = 0.0; + out_8952125250503643232[99] = 0.0; + out_8952125250503643232[100] = 0.0; + out_8952125250503643232[101] = 0.0; + out_8952125250503643232[102] = 0.0; + out_8952125250503643232[103] = 0.0; + out_8952125250503643232[104] = 0.0; + out_8952125250503643232[105] = 0.0; + out_8952125250503643232[106] = 0.0; + out_8952125250503643232[107] = 0.0; + out_8952125250503643232[108] = 0.0; + out_8952125250503643232[109] = 0.0; + out_8952125250503643232[110] = 0.0; + out_8952125250503643232[111] = 0.0; + out_8952125250503643232[112] = 0.0; + out_8952125250503643232[113] = 0.0; + out_8952125250503643232[114] = 1.0; + out_8952125250503643232[115] = 0.0; + out_8952125250503643232[116] = 0.0; + out_8952125250503643232[117] = 0.0; + out_8952125250503643232[118] = 0.0; + out_8952125250503643232[119] = 0.0; + out_8952125250503643232[120] = 0.0; + out_8952125250503643232[121] = 0.0; + out_8952125250503643232[122] = 0.0; + out_8952125250503643232[123] = 0.0; + out_8952125250503643232[124] = 0.0; + out_8952125250503643232[125] = 0.0; + out_8952125250503643232[126] = 0.0; + out_8952125250503643232[127] = 0.0; + out_8952125250503643232[128] = 0.0; + out_8952125250503643232[129] = 0.0; + out_8952125250503643232[130] = 0.0; + out_8952125250503643232[131] = 0.0; + out_8952125250503643232[132] = 0.0; + out_8952125250503643232[133] = 1.0; + out_8952125250503643232[134] = 0.0; + out_8952125250503643232[135] = 0.0; + out_8952125250503643232[136] = 0.0; + out_8952125250503643232[137] = 0.0; + out_8952125250503643232[138] = 0.0; + out_8952125250503643232[139] = 0.0; + out_8952125250503643232[140] = 0.0; + out_8952125250503643232[141] = 0.0; + out_8952125250503643232[142] = 0.0; + out_8952125250503643232[143] = 0.0; + out_8952125250503643232[144] = 0.0; + out_8952125250503643232[145] = 0.0; + out_8952125250503643232[146] = 0.0; + out_8952125250503643232[147] = 0.0; + out_8952125250503643232[148] = 0.0; + out_8952125250503643232[149] = 0.0; + out_8952125250503643232[150] = 0.0; + out_8952125250503643232[151] = 0.0; + out_8952125250503643232[152] = 1.0; + out_8952125250503643232[153] = 0.0; + out_8952125250503643232[154] = 0.0; + out_8952125250503643232[155] = 0.0; + out_8952125250503643232[156] = 0.0; + out_8952125250503643232[157] = 0.0; + out_8952125250503643232[158] = 0.0; + out_8952125250503643232[159] = 0.0; + out_8952125250503643232[160] = 0.0; + out_8952125250503643232[161] = 0.0; + out_8952125250503643232[162] = 0.0; + out_8952125250503643232[163] = 0.0; + out_8952125250503643232[164] = 0.0; + out_8952125250503643232[165] = 0.0; + out_8952125250503643232[166] = 0.0; + out_8952125250503643232[167] = 0.0; + out_8952125250503643232[168] = 0.0; + out_8952125250503643232[169] = 0.0; + out_8952125250503643232[170] = 0.0; + out_8952125250503643232[171] = 1.0; + out_8952125250503643232[172] = 0.0; + out_8952125250503643232[173] = 0.0; + out_8952125250503643232[174] = 0.0; + out_8952125250503643232[175] = 0.0; + out_8952125250503643232[176] = 0.0; + out_8952125250503643232[177] = 0.0; + out_8952125250503643232[178] = 0.0; + out_8952125250503643232[179] = 0.0; + out_8952125250503643232[180] = 0.0; + out_8952125250503643232[181] = 0.0; + out_8952125250503643232[182] = 0.0; + out_8952125250503643232[183] = 0.0; + out_8952125250503643232[184] = 0.0; + out_8952125250503643232[185] = 0.0; + out_8952125250503643232[186] = 0.0; + out_8952125250503643232[187] = 0.0; + out_8952125250503643232[188] = 0.0; + out_8952125250503643232[189] = 0.0; + out_8952125250503643232[190] = 1.0; + out_8952125250503643232[191] = 0.0; + out_8952125250503643232[192] = 0.0; + out_8952125250503643232[193] = 0.0; + out_8952125250503643232[194] = 0.0; + out_8952125250503643232[195] = 0.0; + out_8952125250503643232[196] = 0.0; + out_8952125250503643232[197] = 0.0; + out_8952125250503643232[198] = 0.0; + out_8952125250503643232[199] = 0.0; + out_8952125250503643232[200] = 0.0; + out_8952125250503643232[201] = 0.0; + out_8952125250503643232[202] = 0.0; + out_8952125250503643232[203] = 0.0; + out_8952125250503643232[204] = 0.0; + out_8952125250503643232[205] = 0.0; + out_8952125250503643232[206] = 0.0; + out_8952125250503643232[207] = 0.0; + out_8952125250503643232[208] = 0.0; + out_8952125250503643232[209] = 1.0; + out_8952125250503643232[210] = 0.0; + out_8952125250503643232[211] = 0.0; + out_8952125250503643232[212] = 0.0; + out_8952125250503643232[213] = 0.0; + out_8952125250503643232[214] = 0.0; + out_8952125250503643232[215] = 0.0; + out_8952125250503643232[216] = 0.0; + out_8952125250503643232[217] = 0.0; + out_8952125250503643232[218] = 0.0; + out_8952125250503643232[219] = 0.0; + out_8952125250503643232[220] = 0.0; + out_8952125250503643232[221] = 0.0; + out_8952125250503643232[222] = 0.0; + out_8952125250503643232[223] = 0.0; + out_8952125250503643232[224] = 0.0; + out_8952125250503643232[225] = 0.0; + out_8952125250503643232[226] = 0.0; + out_8952125250503643232[227] = 0.0; + out_8952125250503643232[228] = 1.0; + out_8952125250503643232[229] = 0.0; + out_8952125250503643232[230] = 0.0; + out_8952125250503643232[231] = 0.0; + out_8952125250503643232[232] = 0.0; + out_8952125250503643232[233] = 0.0; + out_8952125250503643232[234] = 0.0; + out_8952125250503643232[235] = 0.0; + out_8952125250503643232[236] = 0.0; + out_8952125250503643232[237] = 0.0; + out_8952125250503643232[238] = 0.0; + out_8952125250503643232[239] = 0.0; + out_8952125250503643232[240] = 0.0; + out_8952125250503643232[241] = 0.0; + out_8952125250503643232[242] = 0.0; + out_8952125250503643232[243] = 0.0; + out_8952125250503643232[244] = 0.0; + out_8952125250503643232[245] = 0.0; + out_8952125250503643232[246] = 0.0; + out_8952125250503643232[247] = 1.0; + out_8952125250503643232[248] = 0.0; + out_8952125250503643232[249] = 0.0; + out_8952125250503643232[250] = 0.0; + out_8952125250503643232[251] = 0.0; + out_8952125250503643232[252] = 0.0; + out_8952125250503643232[253] = 0.0; + out_8952125250503643232[254] = 0.0; + out_8952125250503643232[255] = 0.0; + out_8952125250503643232[256] = 0.0; + out_8952125250503643232[257] = 0.0; + out_8952125250503643232[258] = 0.0; + out_8952125250503643232[259] = 0.0; + out_8952125250503643232[260] = 0.0; + out_8952125250503643232[261] = 0.0; + out_8952125250503643232[262] = 0.0; + out_8952125250503643232[263] = 0.0; + out_8952125250503643232[264] = 0.0; + out_8952125250503643232[265] = 0.0; + out_8952125250503643232[266] = 1.0; + out_8952125250503643232[267] = 0.0; + out_8952125250503643232[268] = 0.0; + out_8952125250503643232[269] = 0.0; + out_8952125250503643232[270] = 0.0; + out_8952125250503643232[271] = 0.0; + out_8952125250503643232[272] = 0.0; + out_8952125250503643232[273] = 0.0; + out_8952125250503643232[274] = 0.0; + out_8952125250503643232[275] = 0.0; + out_8952125250503643232[276] = 0.0; + out_8952125250503643232[277] = 0.0; + out_8952125250503643232[278] = 0.0; + out_8952125250503643232[279] = 0.0; + out_8952125250503643232[280] = 0.0; + out_8952125250503643232[281] = 0.0; + out_8952125250503643232[282] = 0.0; + out_8952125250503643232[283] = 0.0; + out_8952125250503643232[284] = 0.0; + out_8952125250503643232[285] = 1.0; + out_8952125250503643232[286] = 0.0; + out_8952125250503643232[287] = 0.0; + out_8952125250503643232[288] = 0.0; + out_8952125250503643232[289] = 0.0; + out_8952125250503643232[290] = 0.0; + out_8952125250503643232[291] = 0.0; + out_8952125250503643232[292] = 0.0; + out_8952125250503643232[293] = 0.0; + out_8952125250503643232[294] = 0.0; + out_8952125250503643232[295] = 0.0; + out_8952125250503643232[296] = 0.0; + out_8952125250503643232[297] = 0.0; + out_8952125250503643232[298] = 0.0; + out_8952125250503643232[299] = 0.0; + out_8952125250503643232[300] = 0.0; + out_8952125250503643232[301] = 0.0; + out_8952125250503643232[302] = 0.0; + out_8952125250503643232[303] = 0.0; + out_8952125250503643232[304] = 1.0; + out_8952125250503643232[305] = 0.0; + out_8952125250503643232[306] = 0.0; + out_8952125250503643232[307] = 0.0; + out_8952125250503643232[308] = 0.0; + out_8952125250503643232[309] = 0.0; + out_8952125250503643232[310] = 0.0; + out_8952125250503643232[311] = 0.0; + out_8952125250503643232[312] = 0.0; + out_8952125250503643232[313] = 0.0; + out_8952125250503643232[314] = 0.0; + out_8952125250503643232[315] = 0.0; + out_8952125250503643232[316] = 0.0; + out_8952125250503643232[317] = 0.0; + out_8952125250503643232[318] = 0.0; + out_8952125250503643232[319] = 0.0; + out_8952125250503643232[320] = 0.0; + out_8952125250503643232[321] = 0.0; + out_8952125250503643232[322] = 0.0; + out_8952125250503643232[323] = 1.0; } -void f_fun(double *state, double dt, double *out_9094503671864348345) { - out_9094503671864348345[0] = atan2((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), -(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1])); - out_9094503671864348345[1] = asin(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8])); - out_9094503671864348345[2] = atan2(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), -(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2])); - out_9094503671864348345[3] = dt*state[12] + state[3]; - out_9094503671864348345[4] = dt*state[13] + state[4]; - out_9094503671864348345[5] = dt*state[14] + state[5]; - out_9094503671864348345[6] = state[6]; - out_9094503671864348345[7] = state[7]; - out_9094503671864348345[8] = state[8]; - out_9094503671864348345[9] = state[9]; - out_9094503671864348345[10] = state[10]; - out_9094503671864348345[11] = state[11]; - out_9094503671864348345[12] = state[12]; - out_9094503671864348345[13] = state[13]; - out_9094503671864348345[14] = state[14]; - out_9094503671864348345[15] = state[15]; - out_9094503671864348345[16] = state[16]; - out_9094503671864348345[17] = state[17]; +void f_fun(double *state, double dt, double *out_3519678704568830866) { + out_3519678704568830866[0] = atan2((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), -(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1])); + out_3519678704568830866[1] = asin(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8])); + out_3519678704568830866[2] = atan2(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), -(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2])); + out_3519678704568830866[3] = dt*state[12] + state[3]; + out_3519678704568830866[4] = dt*state[13] + state[4]; + out_3519678704568830866[5] = dt*state[14] + state[5]; + out_3519678704568830866[6] = state[6]; + out_3519678704568830866[7] = state[7]; + out_3519678704568830866[8] = state[8]; + out_3519678704568830866[9] = state[9]; + out_3519678704568830866[10] = state[10]; + out_3519678704568830866[11] = state[11]; + out_3519678704568830866[12] = state[12]; + out_3519678704568830866[13] = state[13]; + out_3519678704568830866[14] = state[14]; + out_3519678704568830866[15] = state[15]; + out_3519678704568830866[16] = state[16]; + out_3519678704568830866[17] = state[17]; } -void F_fun(double *state, double dt, double *out_1312959600226932432) { - out_1312959600226932432[0] = ((-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*cos(state[0])*cos(state[1]) - sin(state[0])*cos(dt*state[6])*cos(dt*state[7])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + ((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*cos(state[0])*cos(state[1]) - sin(dt*state[6])*sin(state[0])*cos(dt*state[7])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); - out_1312959600226932432[1] = ((-sin(dt*state[6])*sin(dt*state[8]) - sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*cos(state[1]) - (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*sin(state[1]) - sin(state[1])*cos(dt*state[6])*cos(dt*state[7])*cos(state[0]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + (-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*sin(state[1]) + (-sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) + sin(dt*state[8])*cos(dt*state[6]))*cos(state[1]) - sin(dt*state[6])*sin(state[1])*cos(dt*state[7])*cos(state[0]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); - out_1312959600226932432[2] = 0; - out_1312959600226932432[3] = 0; - out_1312959600226932432[4] = 0; - out_1312959600226932432[5] = 0; - out_1312959600226932432[6] = (-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(dt*cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]) + (-dt*sin(dt*state[6])*sin(dt*state[8]) - dt*sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-dt*sin(dt*state[6])*cos(dt*state[8]) + dt*sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + (-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-dt*sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]) + (-dt*sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) - dt*cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (dt*sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); - out_1312959600226932432[7] = (-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-dt*sin(dt*state[6])*sin(dt*state[7])*cos(state[0])*cos(state[1]) + dt*sin(dt*state[6])*sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) - dt*sin(dt*state[6])*sin(state[1])*cos(dt*state[7])*cos(dt*state[8]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + (-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-dt*sin(dt*state[7])*cos(dt*state[6])*cos(state[0])*cos(state[1]) + dt*sin(dt*state[8])*sin(state[0])*cos(dt*state[6])*cos(dt*state[7])*cos(state[1]) - dt*sin(state[1])*cos(dt*state[6])*cos(dt*state[7])*cos(dt*state[8]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); - out_1312959600226932432[8] = ((dt*sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + dt*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (dt*sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + ((dt*sin(dt*state[6])*sin(dt*state[8]) + dt*sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (-dt*sin(dt*state[6])*cos(dt*state[8]) + dt*sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); - out_1312959600226932432[9] = 0; - out_1312959600226932432[10] = 0; - out_1312959600226932432[11] = 0; - out_1312959600226932432[12] = 0; - out_1312959600226932432[13] = 0; - out_1312959600226932432[14] = 0; - out_1312959600226932432[15] = 0; - out_1312959600226932432[16] = 0; - out_1312959600226932432[17] = 0; - out_1312959600226932432[18] = (-sin(dt*state[7])*sin(state[0])*cos(state[1]) - sin(dt*state[8])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); - out_1312959600226932432[19] = (-sin(dt*state[7])*sin(state[1])*cos(state[0]) + sin(dt*state[8])*sin(state[0])*sin(state[1])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); - out_1312959600226932432[20] = 0; - out_1312959600226932432[21] = 0; - out_1312959600226932432[22] = 0; - out_1312959600226932432[23] = 0; - out_1312959600226932432[24] = 0; - out_1312959600226932432[25] = (dt*sin(dt*state[7])*sin(dt*state[8])*sin(state[0])*cos(state[1]) - dt*sin(dt*state[7])*sin(state[1])*cos(dt*state[8]) + dt*cos(dt*state[7])*cos(state[0])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); - out_1312959600226932432[26] = (-dt*sin(dt*state[8])*sin(state[1])*cos(dt*state[7]) - dt*sin(state[0])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); - out_1312959600226932432[27] = 0; - out_1312959600226932432[28] = 0; - out_1312959600226932432[29] = 0; - out_1312959600226932432[30] = 0; - out_1312959600226932432[31] = 0; - out_1312959600226932432[32] = 0; - out_1312959600226932432[33] = 0; - out_1312959600226932432[34] = 0; - out_1312959600226932432[35] = 0; - out_1312959600226932432[36] = ((sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[7]))*((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[7]))*(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); - out_1312959600226932432[37] = (-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))*(-sin(dt*state[7])*sin(state[2])*cos(state[0])*cos(state[1]) + sin(dt*state[8])*sin(state[0])*sin(state[2])*cos(dt*state[7])*cos(state[1]) - sin(state[1])*sin(state[2])*cos(dt*state[7])*cos(dt*state[8]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))*(-sin(dt*state[7])*cos(state[0])*cos(state[1])*cos(state[2]) + sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1])*cos(state[2]) - sin(state[1])*cos(dt*state[7])*cos(dt*state[8])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); - out_1312959600226932432[38] = ((-sin(state[0])*sin(state[2]) - sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))*(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (-sin(state[0])*sin(state[1])*sin(state[2]) - cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))*((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); - out_1312959600226932432[39] = 0; - out_1312959600226932432[40] = 0; - out_1312959600226932432[41] = 0; - out_1312959600226932432[42] = 0; - out_1312959600226932432[43] = (-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))*(dt*(sin(state[0])*cos(state[2]) - sin(state[1])*sin(state[2])*cos(state[0]))*cos(dt*state[7]) - dt*(sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[7])*sin(dt*state[8]) - dt*sin(dt*state[7])*sin(state[2])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))*(dt*(-sin(state[0])*sin(state[2]) - sin(state[1])*cos(state[0])*cos(state[2]))*cos(dt*state[7]) - dt*(sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[7])*sin(dt*state[8]) - dt*sin(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); - out_1312959600226932432[44] = (dt*(sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*cos(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*sin(state[2])*cos(dt*state[7])*cos(state[1]))*(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + (dt*(sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*cos(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*cos(dt*state[7])*cos(state[1])*cos(state[2]))*((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); - out_1312959600226932432[45] = 0; - out_1312959600226932432[46] = 0; - out_1312959600226932432[47] = 0; - out_1312959600226932432[48] = 0; - out_1312959600226932432[49] = 0; - out_1312959600226932432[50] = 0; - out_1312959600226932432[51] = 0; - out_1312959600226932432[52] = 0; - out_1312959600226932432[53] = 0; - out_1312959600226932432[54] = 0; - out_1312959600226932432[55] = 0; - out_1312959600226932432[56] = 0; - out_1312959600226932432[57] = 1; - out_1312959600226932432[58] = 0; - out_1312959600226932432[59] = 0; - out_1312959600226932432[60] = 0; - out_1312959600226932432[61] = 0; - out_1312959600226932432[62] = 0; - out_1312959600226932432[63] = 0; - out_1312959600226932432[64] = 0; - out_1312959600226932432[65] = 0; - out_1312959600226932432[66] = dt; - out_1312959600226932432[67] = 0; - out_1312959600226932432[68] = 0; - out_1312959600226932432[69] = 0; - out_1312959600226932432[70] = 0; - out_1312959600226932432[71] = 0; - out_1312959600226932432[72] = 0; - out_1312959600226932432[73] = 0; - out_1312959600226932432[74] = 0; - out_1312959600226932432[75] = 0; - out_1312959600226932432[76] = 1; - out_1312959600226932432[77] = 0; - out_1312959600226932432[78] = 0; - out_1312959600226932432[79] = 0; - out_1312959600226932432[80] = 0; - out_1312959600226932432[81] = 0; - out_1312959600226932432[82] = 0; - out_1312959600226932432[83] = 0; - out_1312959600226932432[84] = 0; - out_1312959600226932432[85] = dt; - out_1312959600226932432[86] = 0; - out_1312959600226932432[87] = 0; - out_1312959600226932432[88] = 0; - out_1312959600226932432[89] = 0; - out_1312959600226932432[90] = 0; - out_1312959600226932432[91] = 0; - out_1312959600226932432[92] = 0; - out_1312959600226932432[93] = 0; - out_1312959600226932432[94] = 0; - out_1312959600226932432[95] = 1; - out_1312959600226932432[96] = 0; - out_1312959600226932432[97] = 0; - out_1312959600226932432[98] = 0; - out_1312959600226932432[99] = 0; - out_1312959600226932432[100] = 0; - out_1312959600226932432[101] = 0; - out_1312959600226932432[102] = 0; - out_1312959600226932432[103] = 0; - out_1312959600226932432[104] = dt; - out_1312959600226932432[105] = 0; - out_1312959600226932432[106] = 0; - out_1312959600226932432[107] = 0; - out_1312959600226932432[108] = 0; - out_1312959600226932432[109] = 0; - out_1312959600226932432[110] = 0; - out_1312959600226932432[111] = 0; - out_1312959600226932432[112] = 0; - out_1312959600226932432[113] = 0; - out_1312959600226932432[114] = 1; - out_1312959600226932432[115] = 0; - out_1312959600226932432[116] = 0; - out_1312959600226932432[117] = 0; - out_1312959600226932432[118] = 0; - out_1312959600226932432[119] = 0; - out_1312959600226932432[120] = 0; - out_1312959600226932432[121] = 0; - out_1312959600226932432[122] = 0; - out_1312959600226932432[123] = 0; - out_1312959600226932432[124] = 0; - out_1312959600226932432[125] = 0; - out_1312959600226932432[126] = 0; - out_1312959600226932432[127] = 0; - out_1312959600226932432[128] = 0; - out_1312959600226932432[129] = 0; - out_1312959600226932432[130] = 0; - out_1312959600226932432[131] = 0; - out_1312959600226932432[132] = 0; - out_1312959600226932432[133] = 1; - out_1312959600226932432[134] = 0; - out_1312959600226932432[135] = 0; - out_1312959600226932432[136] = 0; - out_1312959600226932432[137] = 0; - out_1312959600226932432[138] = 0; - out_1312959600226932432[139] = 0; - out_1312959600226932432[140] = 0; - out_1312959600226932432[141] = 0; - out_1312959600226932432[142] = 0; - out_1312959600226932432[143] = 0; - out_1312959600226932432[144] = 0; - out_1312959600226932432[145] = 0; - out_1312959600226932432[146] = 0; - out_1312959600226932432[147] = 0; - out_1312959600226932432[148] = 0; - out_1312959600226932432[149] = 0; - out_1312959600226932432[150] = 0; - out_1312959600226932432[151] = 0; - out_1312959600226932432[152] = 1; - out_1312959600226932432[153] = 0; - out_1312959600226932432[154] = 0; - out_1312959600226932432[155] = 0; - out_1312959600226932432[156] = 0; - out_1312959600226932432[157] = 0; - out_1312959600226932432[158] = 0; - out_1312959600226932432[159] = 0; - out_1312959600226932432[160] = 0; - out_1312959600226932432[161] = 0; - out_1312959600226932432[162] = 0; - out_1312959600226932432[163] = 0; - out_1312959600226932432[164] = 0; - out_1312959600226932432[165] = 0; - out_1312959600226932432[166] = 0; - out_1312959600226932432[167] = 0; - out_1312959600226932432[168] = 0; - out_1312959600226932432[169] = 0; - out_1312959600226932432[170] = 0; - out_1312959600226932432[171] = 1; - out_1312959600226932432[172] = 0; - out_1312959600226932432[173] = 0; - out_1312959600226932432[174] = 0; - out_1312959600226932432[175] = 0; - out_1312959600226932432[176] = 0; - out_1312959600226932432[177] = 0; - out_1312959600226932432[178] = 0; - out_1312959600226932432[179] = 0; - out_1312959600226932432[180] = 0; - out_1312959600226932432[181] = 0; - out_1312959600226932432[182] = 0; - out_1312959600226932432[183] = 0; - out_1312959600226932432[184] = 0; - out_1312959600226932432[185] = 0; - out_1312959600226932432[186] = 0; - out_1312959600226932432[187] = 0; - out_1312959600226932432[188] = 0; - out_1312959600226932432[189] = 0; - out_1312959600226932432[190] = 1; - out_1312959600226932432[191] = 0; - out_1312959600226932432[192] = 0; - out_1312959600226932432[193] = 0; - out_1312959600226932432[194] = 0; - out_1312959600226932432[195] = 0; - out_1312959600226932432[196] = 0; - out_1312959600226932432[197] = 0; - out_1312959600226932432[198] = 0; - out_1312959600226932432[199] = 0; - out_1312959600226932432[200] = 0; - out_1312959600226932432[201] = 0; - out_1312959600226932432[202] = 0; - out_1312959600226932432[203] = 0; - out_1312959600226932432[204] = 0; - out_1312959600226932432[205] = 0; - out_1312959600226932432[206] = 0; - out_1312959600226932432[207] = 0; - out_1312959600226932432[208] = 0; - out_1312959600226932432[209] = 1; - out_1312959600226932432[210] = 0; - out_1312959600226932432[211] = 0; - out_1312959600226932432[212] = 0; - out_1312959600226932432[213] = 0; - out_1312959600226932432[214] = 0; - out_1312959600226932432[215] = 0; - out_1312959600226932432[216] = 0; - out_1312959600226932432[217] = 0; - out_1312959600226932432[218] = 0; - out_1312959600226932432[219] = 0; - out_1312959600226932432[220] = 0; - out_1312959600226932432[221] = 0; - out_1312959600226932432[222] = 0; - out_1312959600226932432[223] = 0; - out_1312959600226932432[224] = 0; - out_1312959600226932432[225] = 0; - out_1312959600226932432[226] = 0; - out_1312959600226932432[227] = 0; - out_1312959600226932432[228] = 1; - out_1312959600226932432[229] = 0; - out_1312959600226932432[230] = 0; - out_1312959600226932432[231] = 0; - out_1312959600226932432[232] = 0; - out_1312959600226932432[233] = 0; - out_1312959600226932432[234] = 0; - out_1312959600226932432[235] = 0; - out_1312959600226932432[236] = 0; - out_1312959600226932432[237] = 0; - out_1312959600226932432[238] = 0; - out_1312959600226932432[239] = 0; - out_1312959600226932432[240] = 0; - out_1312959600226932432[241] = 0; - out_1312959600226932432[242] = 0; - out_1312959600226932432[243] = 0; - out_1312959600226932432[244] = 0; - out_1312959600226932432[245] = 0; - out_1312959600226932432[246] = 0; - out_1312959600226932432[247] = 1; - out_1312959600226932432[248] = 0; - out_1312959600226932432[249] = 0; - out_1312959600226932432[250] = 0; - out_1312959600226932432[251] = 0; - out_1312959600226932432[252] = 0; - out_1312959600226932432[253] = 0; - out_1312959600226932432[254] = 0; - out_1312959600226932432[255] = 0; - out_1312959600226932432[256] = 0; - out_1312959600226932432[257] = 0; - out_1312959600226932432[258] = 0; - out_1312959600226932432[259] = 0; - out_1312959600226932432[260] = 0; - out_1312959600226932432[261] = 0; - out_1312959600226932432[262] = 0; - out_1312959600226932432[263] = 0; - out_1312959600226932432[264] = 0; - out_1312959600226932432[265] = 0; - out_1312959600226932432[266] = 1; - out_1312959600226932432[267] = 0; - out_1312959600226932432[268] = 0; - out_1312959600226932432[269] = 0; - out_1312959600226932432[270] = 0; - out_1312959600226932432[271] = 0; - out_1312959600226932432[272] = 0; - out_1312959600226932432[273] = 0; - out_1312959600226932432[274] = 0; - out_1312959600226932432[275] = 0; - out_1312959600226932432[276] = 0; - out_1312959600226932432[277] = 0; - out_1312959600226932432[278] = 0; - out_1312959600226932432[279] = 0; - out_1312959600226932432[280] = 0; - out_1312959600226932432[281] = 0; - out_1312959600226932432[282] = 0; - out_1312959600226932432[283] = 0; - out_1312959600226932432[284] = 0; - out_1312959600226932432[285] = 1; - out_1312959600226932432[286] = 0; - out_1312959600226932432[287] = 0; - out_1312959600226932432[288] = 0; - out_1312959600226932432[289] = 0; - out_1312959600226932432[290] = 0; - out_1312959600226932432[291] = 0; - out_1312959600226932432[292] = 0; - out_1312959600226932432[293] = 0; - out_1312959600226932432[294] = 0; - out_1312959600226932432[295] = 0; - out_1312959600226932432[296] = 0; - out_1312959600226932432[297] = 0; - out_1312959600226932432[298] = 0; - out_1312959600226932432[299] = 0; - out_1312959600226932432[300] = 0; - out_1312959600226932432[301] = 0; - out_1312959600226932432[302] = 0; - out_1312959600226932432[303] = 0; - out_1312959600226932432[304] = 1; - out_1312959600226932432[305] = 0; - out_1312959600226932432[306] = 0; - out_1312959600226932432[307] = 0; - out_1312959600226932432[308] = 0; - out_1312959600226932432[309] = 0; - out_1312959600226932432[310] = 0; - out_1312959600226932432[311] = 0; - out_1312959600226932432[312] = 0; - out_1312959600226932432[313] = 0; - out_1312959600226932432[314] = 0; - out_1312959600226932432[315] = 0; - out_1312959600226932432[316] = 0; - out_1312959600226932432[317] = 0; - out_1312959600226932432[318] = 0; - out_1312959600226932432[319] = 0; - out_1312959600226932432[320] = 0; - out_1312959600226932432[321] = 0; - out_1312959600226932432[322] = 0; - out_1312959600226932432[323] = 1; +void F_fun(double *state, double dt, double *out_6750093296288889328) { + out_6750093296288889328[0] = ((-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*cos(state[0])*cos(state[1]) - sin(state[0])*cos(dt*state[6])*cos(dt*state[7])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + ((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*cos(state[0])*cos(state[1]) - sin(dt*state[6])*sin(state[0])*cos(dt*state[7])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); + out_6750093296288889328[1] = ((-sin(dt*state[6])*sin(dt*state[8]) - sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*cos(state[1]) - (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*sin(state[1]) - sin(state[1])*cos(dt*state[6])*cos(dt*state[7])*cos(state[0]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + (-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*sin(state[1]) + (-sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) + sin(dt*state[8])*cos(dt*state[6]))*cos(state[1]) - sin(dt*state[6])*sin(state[1])*cos(dt*state[7])*cos(state[0]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); + out_6750093296288889328[2] = 0; + out_6750093296288889328[3] = 0; + out_6750093296288889328[4] = 0; + out_6750093296288889328[5] = 0; + out_6750093296288889328[6] = (-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(dt*cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]) + (-dt*sin(dt*state[6])*sin(dt*state[8]) - dt*sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-dt*sin(dt*state[6])*cos(dt*state[8]) + dt*sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + (-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-dt*sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]) + (-dt*sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) - dt*cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (dt*sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); + out_6750093296288889328[7] = (-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-dt*sin(dt*state[6])*sin(dt*state[7])*cos(state[0])*cos(state[1]) + dt*sin(dt*state[6])*sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) - dt*sin(dt*state[6])*sin(state[1])*cos(dt*state[7])*cos(dt*state[8]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + (-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))*(-dt*sin(dt*state[7])*cos(dt*state[6])*cos(state[0])*cos(state[1]) + dt*sin(dt*state[8])*sin(state[0])*cos(dt*state[6])*cos(dt*state[7])*cos(state[1]) - dt*sin(state[1])*cos(dt*state[6])*cos(dt*state[7])*cos(dt*state[8]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); + out_6750093296288889328[8] = ((dt*sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + dt*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (dt*sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]))*(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)) + ((dt*sin(dt*state[6])*sin(dt*state[8]) + dt*sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (-dt*sin(dt*state[6])*cos(dt*state[8]) + dt*sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]))*(-(sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) + (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) - sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/(pow(-(sin(dt*state[6])*sin(dt*state[8]) + sin(dt*state[7])*cos(dt*state[6])*cos(dt*state[8]))*sin(state[1]) + (-sin(dt*state[6])*cos(dt*state[8]) + sin(dt*state[7])*sin(dt*state[8])*cos(dt*state[6]))*sin(state[0])*cos(state[1]) + cos(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2) + pow((sin(dt*state[6])*sin(dt*state[7])*sin(dt*state[8]) + cos(dt*state[6])*cos(dt*state[8]))*sin(state[0])*cos(state[1]) - (sin(dt*state[6])*sin(dt*state[7])*cos(dt*state[8]) - sin(dt*state[8])*cos(dt*state[6]))*sin(state[1]) + sin(dt*state[6])*cos(dt*state[7])*cos(state[0])*cos(state[1]), 2)); + out_6750093296288889328[9] = 0; + out_6750093296288889328[10] = 0; + out_6750093296288889328[11] = 0; + out_6750093296288889328[12] = 0; + out_6750093296288889328[13] = 0; + out_6750093296288889328[14] = 0; + out_6750093296288889328[15] = 0; + out_6750093296288889328[16] = 0; + out_6750093296288889328[17] = 0; + out_6750093296288889328[18] = (-sin(dt*state[7])*sin(state[0])*cos(state[1]) - sin(dt*state[8])*cos(dt*state[7])*cos(state[0])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); + out_6750093296288889328[19] = (-sin(dt*state[7])*sin(state[1])*cos(state[0]) + sin(dt*state[8])*sin(state[0])*sin(state[1])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); + out_6750093296288889328[20] = 0; + out_6750093296288889328[21] = 0; + out_6750093296288889328[22] = 0; + out_6750093296288889328[23] = 0; + out_6750093296288889328[24] = 0; + out_6750093296288889328[25] = (dt*sin(dt*state[7])*sin(dt*state[8])*sin(state[0])*cos(state[1]) - dt*sin(dt*state[7])*sin(state[1])*cos(dt*state[8]) + dt*cos(dt*state[7])*cos(state[0])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); + out_6750093296288889328[26] = (-dt*sin(dt*state[8])*sin(state[1])*cos(dt*state[7]) - dt*sin(state[0])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/sqrt(1 - pow(sin(dt*state[7])*cos(state[0])*cos(state[1]) - sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1]) + sin(state[1])*cos(dt*state[7])*cos(dt*state[8]), 2)); + out_6750093296288889328[27] = 0; + out_6750093296288889328[28] = 0; + out_6750093296288889328[29] = 0; + out_6750093296288889328[30] = 0; + out_6750093296288889328[31] = 0; + out_6750093296288889328[32] = 0; + out_6750093296288889328[33] = 0; + out_6750093296288889328[34] = 0; + out_6750093296288889328[35] = 0; + out_6750093296288889328[36] = ((sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[7]))*((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[7]))*(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); + out_6750093296288889328[37] = (-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))*(-sin(dt*state[7])*sin(state[2])*cos(state[0])*cos(state[1]) + sin(dt*state[8])*sin(state[0])*sin(state[2])*cos(dt*state[7])*cos(state[1]) - sin(state[1])*sin(state[2])*cos(dt*state[7])*cos(dt*state[8]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))*(-sin(dt*state[7])*cos(state[0])*cos(state[1])*cos(state[2]) + sin(dt*state[8])*sin(state[0])*cos(dt*state[7])*cos(state[1])*cos(state[2]) - sin(state[1])*cos(dt*state[7])*cos(dt*state[8])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); + out_6750093296288889328[38] = ((-sin(state[0])*sin(state[2]) - sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))*(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (-sin(state[0])*sin(state[1])*sin(state[2]) - cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))*((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); + out_6750093296288889328[39] = 0; + out_6750093296288889328[40] = 0; + out_6750093296288889328[41] = 0; + out_6750093296288889328[42] = 0; + out_6750093296288889328[43] = (-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))*(dt*(sin(state[0])*cos(state[2]) - sin(state[1])*sin(state[2])*cos(state[0]))*cos(dt*state[7]) - dt*(sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[7])*sin(dt*state[8]) - dt*sin(dt*state[7])*sin(state[2])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + ((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))*(dt*(-sin(state[0])*sin(state[2]) - sin(state[1])*cos(state[0])*cos(state[2]))*cos(dt*state[7]) - dt*(sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[7])*sin(dt*state[8]) - dt*sin(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); + out_6750093296288889328[44] = (dt*(sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*cos(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*sin(state[2])*cos(dt*state[7])*cos(state[1]))*(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)) + (dt*(sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*cos(dt*state[7])*cos(dt*state[8]) - dt*sin(dt*state[8])*cos(dt*state[7])*cos(state[1])*cos(state[2]))*((-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) - (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) - sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]))/(pow(-(sin(state[0])*sin(state[2]) + sin(state[1])*cos(state[0])*cos(state[2]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*cos(state[2]) - sin(state[2])*cos(state[0]))*sin(dt*state[8])*cos(dt*state[7]) + cos(dt*state[7])*cos(dt*state[8])*cos(state[1])*cos(state[2]), 2) + pow(-(-sin(state[0])*cos(state[2]) + sin(state[1])*sin(state[2])*cos(state[0]))*sin(dt*state[7]) + (sin(state[0])*sin(state[1])*sin(state[2]) + cos(state[0])*cos(state[2]))*sin(dt*state[8])*cos(dt*state[7]) + sin(state[2])*cos(dt*state[7])*cos(dt*state[8])*cos(state[1]), 2)); + out_6750093296288889328[45] = 0; + out_6750093296288889328[46] = 0; + out_6750093296288889328[47] = 0; + out_6750093296288889328[48] = 0; + out_6750093296288889328[49] = 0; + out_6750093296288889328[50] = 0; + out_6750093296288889328[51] = 0; + out_6750093296288889328[52] = 0; + out_6750093296288889328[53] = 0; + out_6750093296288889328[54] = 0; + out_6750093296288889328[55] = 0; + out_6750093296288889328[56] = 0; + out_6750093296288889328[57] = 1; + out_6750093296288889328[58] = 0; + out_6750093296288889328[59] = 0; + out_6750093296288889328[60] = 0; + out_6750093296288889328[61] = 0; + out_6750093296288889328[62] = 0; + out_6750093296288889328[63] = 0; + out_6750093296288889328[64] = 0; + out_6750093296288889328[65] = 0; + out_6750093296288889328[66] = dt; + out_6750093296288889328[67] = 0; + out_6750093296288889328[68] = 0; + out_6750093296288889328[69] = 0; + out_6750093296288889328[70] = 0; + out_6750093296288889328[71] = 0; + out_6750093296288889328[72] = 0; + out_6750093296288889328[73] = 0; + out_6750093296288889328[74] = 0; + out_6750093296288889328[75] = 0; + out_6750093296288889328[76] = 1; + out_6750093296288889328[77] = 0; + out_6750093296288889328[78] = 0; + out_6750093296288889328[79] = 0; + out_6750093296288889328[80] = 0; + out_6750093296288889328[81] = 0; + out_6750093296288889328[82] = 0; + out_6750093296288889328[83] = 0; + out_6750093296288889328[84] = 0; + out_6750093296288889328[85] = dt; + out_6750093296288889328[86] = 0; + out_6750093296288889328[87] = 0; + out_6750093296288889328[88] = 0; + out_6750093296288889328[89] = 0; + out_6750093296288889328[90] = 0; + out_6750093296288889328[91] = 0; + out_6750093296288889328[92] = 0; + out_6750093296288889328[93] = 0; + out_6750093296288889328[94] = 0; + out_6750093296288889328[95] = 1; + out_6750093296288889328[96] = 0; + out_6750093296288889328[97] = 0; + out_6750093296288889328[98] = 0; + out_6750093296288889328[99] = 0; + out_6750093296288889328[100] = 0; + out_6750093296288889328[101] = 0; + out_6750093296288889328[102] = 0; + out_6750093296288889328[103] = 0; + out_6750093296288889328[104] = dt; + out_6750093296288889328[105] = 0; + out_6750093296288889328[106] = 0; + out_6750093296288889328[107] = 0; + out_6750093296288889328[108] = 0; + out_6750093296288889328[109] = 0; + out_6750093296288889328[110] = 0; + out_6750093296288889328[111] = 0; + out_6750093296288889328[112] = 0; + out_6750093296288889328[113] = 0; + out_6750093296288889328[114] = 1; + out_6750093296288889328[115] = 0; + out_6750093296288889328[116] = 0; + out_6750093296288889328[117] = 0; + out_6750093296288889328[118] = 0; + out_6750093296288889328[119] = 0; + out_6750093296288889328[120] = 0; + out_6750093296288889328[121] = 0; + out_6750093296288889328[122] = 0; + out_6750093296288889328[123] = 0; + out_6750093296288889328[124] = 0; + out_6750093296288889328[125] = 0; + out_6750093296288889328[126] = 0; + out_6750093296288889328[127] = 0; + out_6750093296288889328[128] = 0; + out_6750093296288889328[129] = 0; + out_6750093296288889328[130] = 0; + out_6750093296288889328[131] = 0; + out_6750093296288889328[132] = 0; + out_6750093296288889328[133] = 1; + out_6750093296288889328[134] = 0; + out_6750093296288889328[135] = 0; + out_6750093296288889328[136] = 0; + out_6750093296288889328[137] = 0; + out_6750093296288889328[138] = 0; + out_6750093296288889328[139] = 0; + out_6750093296288889328[140] = 0; + out_6750093296288889328[141] = 0; + out_6750093296288889328[142] = 0; + out_6750093296288889328[143] = 0; + out_6750093296288889328[144] = 0; + out_6750093296288889328[145] = 0; + out_6750093296288889328[146] = 0; + out_6750093296288889328[147] = 0; + out_6750093296288889328[148] = 0; + out_6750093296288889328[149] = 0; + out_6750093296288889328[150] = 0; + out_6750093296288889328[151] = 0; + out_6750093296288889328[152] = 1; + out_6750093296288889328[153] = 0; + out_6750093296288889328[154] = 0; + out_6750093296288889328[155] = 0; + out_6750093296288889328[156] = 0; + out_6750093296288889328[157] = 0; + out_6750093296288889328[158] = 0; + out_6750093296288889328[159] = 0; + out_6750093296288889328[160] = 0; + out_6750093296288889328[161] = 0; + out_6750093296288889328[162] = 0; + out_6750093296288889328[163] = 0; + out_6750093296288889328[164] = 0; + out_6750093296288889328[165] = 0; + out_6750093296288889328[166] = 0; + out_6750093296288889328[167] = 0; + out_6750093296288889328[168] = 0; + out_6750093296288889328[169] = 0; + out_6750093296288889328[170] = 0; + out_6750093296288889328[171] = 1; + out_6750093296288889328[172] = 0; + out_6750093296288889328[173] = 0; + out_6750093296288889328[174] = 0; + out_6750093296288889328[175] = 0; + out_6750093296288889328[176] = 0; + out_6750093296288889328[177] = 0; + out_6750093296288889328[178] = 0; + out_6750093296288889328[179] = 0; + out_6750093296288889328[180] = 0; + out_6750093296288889328[181] = 0; + out_6750093296288889328[182] = 0; + out_6750093296288889328[183] = 0; + out_6750093296288889328[184] = 0; + out_6750093296288889328[185] = 0; + out_6750093296288889328[186] = 0; + out_6750093296288889328[187] = 0; + out_6750093296288889328[188] = 0; + out_6750093296288889328[189] = 0; + out_6750093296288889328[190] = 1; + out_6750093296288889328[191] = 0; + out_6750093296288889328[192] = 0; + out_6750093296288889328[193] = 0; + out_6750093296288889328[194] = 0; + out_6750093296288889328[195] = 0; + out_6750093296288889328[196] = 0; + out_6750093296288889328[197] = 0; + out_6750093296288889328[198] = 0; + out_6750093296288889328[199] = 0; + out_6750093296288889328[200] = 0; + out_6750093296288889328[201] = 0; + out_6750093296288889328[202] = 0; + out_6750093296288889328[203] = 0; + out_6750093296288889328[204] = 0; + out_6750093296288889328[205] = 0; + out_6750093296288889328[206] = 0; + out_6750093296288889328[207] = 0; + out_6750093296288889328[208] = 0; + out_6750093296288889328[209] = 1; + out_6750093296288889328[210] = 0; + out_6750093296288889328[211] = 0; + out_6750093296288889328[212] = 0; + out_6750093296288889328[213] = 0; + out_6750093296288889328[214] = 0; + out_6750093296288889328[215] = 0; + out_6750093296288889328[216] = 0; + out_6750093296288889328[217] = 0; + out_6750093296288889328[218] = 0; + out_6750093296288889328[219] = 0; + out_6750093296288889328[220] = 0; + out_6750093296288889328[221] = 0; + out_6750093296288889328[222] = 0; + out_6750093296288889328[223] = 0; + out_6750093296288889328[224] = 0; + out_6750093296288889328[225] = 0; + out_6750093296288889328[226] = 0; + out_6750093296288889328[227] = 0; + out_6750093296288889328[228] = 1; + out_6750093296288889328[229] = 0; + out_6750093296288889328[230] = 0; + out_6750093296288889328[231] = 0; + out_6750093296288889328[232] = 0; + out_6750093296288889328[233] = 0; + out_6750093296288889328[234] = 0; + out_6750093296288889328[235] = 0; + out_6750093296288889328[236] = 0; + out_6750093296288889328[237] = 0; + out_6750093296288889328[238] = 0; + out_6750093296288889328[239] = 0; + out_6750093296288889328[240] = 0; + out_6750093296288889328[241] = 0; + out_6750093296288889328[242] = 0; + out_6750093296288889328[243] = 0; + out_6750093296288889328[244] = 0; + out_6750093296288889328[245] = 0; + out_6750093296288889328[246] = 0; + out_6750093296288889328[247] = 1; + out_6750093296288889328[248] = 0; + out_6750093296288889328[249] = 0; + out_6750093296288889328[250] = 0; + out_6750093296288889328[251] = 0; + out_6750093296288889328[252] = 0; + out_6750093296288889328[253] = 0; + out_6750093296288889328[254] = 0; + out_6750093296288889328[255] = 0; + out_6750093296288889328[256] = 0; + out_6750093296288889328[257] = 0; + out_6750093296288889328[258] = 0; + out_6750093296288889328[259] = 0; + out_6750093296288889328[260] = 0; + out_6750093296288889328[261] = 0; + out_6750093296288889328[262] = 0; + out_6750093296288889328[263] = 0; + out_6750093296288889328[264] = 0; + out_6750093296288889328[265] = 0; + out_6750093296288889328[266] = 1; + out_6750093296288889328[267] = 0; + out_6750093296288889328[268] = 0; + out_6750093296288889328[269] = 0; + out_6750093296288889328[270] = 0; + out_6750093296288889328[271] = 0; + out_6750093296288889328[272] = 0; + out_6750093296288889328[273] = 0; + out_6750093296288889328[274] = 0; + out_6750093296288889328[275] = 0; + out_6750093296288889328[276] = 0; + out_6750093296288889328[277] = 0; + out_6750093296288889328[278] = 0; + out_6750093296288889328[279] = 0; + out_6750093296288889328[280] = 0; + out_6750093296288889328[281] = 0; + out_6750093296288889328[282] = 0; + out_6750093296288889328[283] = 0; + out_6750093296288889328[284] = 0; + out_6750093296288889328[285] = 1; + out_6750093296288889328[286] = 0; + out_6750093296288889328[287] = 0; + out_6750093296288889328[288] = 0; + out_6750093296288889328[289] = 0; + out_6750093296288889328[290] = 0; + out_6750093296288889328[291] = 0; + out_6750093296288889328[292] = 0; + out_6750093296288889328[293] = 0; + out_6750093296288889328[294] = 0; + out_6750093296288889328[295] = 0; + out_6750093296288889328[296] = 0; + out_6750093296288889328[297] = 0; + out_6750093296288889328[298] = 0; + out_6750093296288889328[299] = 0; + out_6750093296288889328[300] = 0; + out_6750093296288889328[301] = 0; + out_6750093296288889328[302] = 0; + out_6750093296288889328[303] = 0; + out_6750093296288889328[304] = 1; + out_6750093296288889328[305] = 0; + out_6750093296288889328[306] = 0; + out_6750093296288889328[307] = 0; + out_6750093296288889328[308] = 0; + out_6750093296288889328[309] = 0; + out_6750093296288889328[310] = 0; + out_6750093296288889328[311] = 0; + out_6750093296288889328[312] = 0; + out_6750093296288889328[313] = 0; + out_6750093296288889328[314] = 0; + out_6750093296288889328[315] = 0; + out_6750093296288889328[316] = 0; + out_6750093296288889328[317] = 0; + out_6750093296288889328[318] = 0; + out_6750093296288889328[319] = 0; + out_6750093296288889328[320] = 0; + out_6750093296288889328[321] = 0; + out_6750093296288889328[322] = 0; + out_6750093296288889328[323] = 1; } -void h_4(double *state, double *unused, double *out_6400948089178504221) { - out_6400948089178504221[0] = state[6] + state[9]; - out_6400948089178504221[1] = state[7] + state[10]; - out_6400948089178504221[2] = state[8] + state[11]; +void h_4(double *state, double *unused, double *out_1078897140345555822) { + out_1078897140345555822[0] = state[6] + state[9]; + out_1078897140345555822[1] = state[7] + state[10]; + out_1078897140345555822[2] = state[8] + state[11]; } -void H_4(double *state, double *unused, double *out_3419471307660667524) { - out_3419471307660667524[0] = 0; - out_3419471307660667524[1] = 0; - out_3419471307660667524[2] = 0; - out_3419471307660667524[3] = 0; - out_3419471307660667524[4] = 0; - out_3419471307660667524[5] = 0; - out_3419471307660667524[6] = 1; - out_3419471307660667524[7] = 0; - out_3419471307660667524[8] = 0; - out_3419471307660667524[9] = 1; - out_3419471307660667524[10] = 0; - out_3419471307660667524[11] = 0; - out_3419471307660667524[12] = 0; - out_3419471307660667524[13] = 0; - out_3419471307660667524[14] = 0; - out_3419471307660667524[15] = 0; - out_3419471307660667524[16] = 0; - out_3419471307660667524[17] = 0; - out_3419471307660667524[18] = 0; - out_3419471307660667524[19] = 0; - out_3419471307660667524[20] = 0; - out_3419471307660667524[21] = 0; - out_3419471307660667524[22] = 0; - out_3419471307660667524[23] = 0; - out_3419471307660667524[24] = 0; - out_3419471307660667524[25] = 1; - out_3419471307660667524[26] = 0; - out_3419471307660667524[27] = 0; - out_3419471307660667524[28] = 1; - out_3419471307660667524[29] = 0; - out_3419471307660667524[30] = 0; - out_3419471307660667524[31] = 0; - out_3419471307660667524[32] = 0; - out_3419471307660667524[33] = 0; - out_3419471307660667524[34] = 0; - out_3419471307660667524[35] = 0; - out_3419471307660667524[36] = 0; - out_3419471307660667524[37] = 0; - out_3419471307660667524[38] = 0; - out_3419471307660667524[39] = 0; - out_3419471307660667524[40] = 0; - out_3419471307660667524[41] = 0; - out_3419471307660667524[42] = 0; - out_3419471307660667524[43] = 0; - out_3419471307660667524[44] = 1; - out_3419471307660667524[45] = 0; - out_3419471307660667524[46] = 0; - out_3419471307660667524[47] = 1; - out_3419471307660667524[48] = 0; - out_3419471307660667524[49] = 0; - out_3419471307660667524[50] = 0; - out_3419471307660667524[51] = 0; - out_3419471307660667524[52] = 0; - out_3419471307660667524[53] = 0; +void H_4(double *state, double *unused, double *out_850583411531230682) { + out_850583411531230682[0] = 0; + out_850583411531230682[1] = 0; + out_850583411531230682[2] = 0; + out_850583411531230682[3] = 0; + out_850583411531230682[4] = 0; + out_850583411531230682[5] = 0; + out_850583411531230682[6] = 1; + out_850583411531230682[7] = 0; + out_850583411531230682[8] = 0; + out_850583411531230682[9] = 1; + out_850583411531230682[10] = 0; + out_850583411531230682[11] = 0; + out_850583411531230682[12] = 0; + out_850583411531230682[13] = 0; + out_850583411531230682[14] = 0; + out_850583411531230682[15] = 0; + out_850583411531230682[16] = 0; + out_850583411531230682[17] = 0; + out_850583411531230682[18] = 0; + out_850583411531230682[19] = 0; + out_850583411531230682[20] = 0; + out_850583411531230682[21] = 0; + out_850583411531230682[22] = 0; + out_850583411531230682[23] = 0; + out_850583411531230682[24] = 0; + out_850583411531230682[25] = 1; + out_850583411531230682[26] = 0; + out_850583411531230682[27] = 0; + out_850583411531230682[28] = 1; + out_850583411531230682[29] = 0; + out_850583411531230682[30] = 0; + out_850583411531230682[31] = 0; + out_850583411531230682[32] = 0; + out_850583411531230682[33] = 0; + out_850583411531230682[34] = 0; + out_850583411531230682[35] = 0; + out_850583411531230682[36] = 0; + out_850583411531230682[37] = 0; + out_850583411531230682[38] = 0; + out_850583411531230682[39] = 0; + out_850583411531230682[40] = 0; + out_850583411531230682[41] = 0; + out_850583411531230682[42] = 0; + out_850583411531230682[43] = 0; + out_850583411531230682[44] = 1; + out_850583411531230682[45] = 0; + out_850583411531230682[46] = 0; + out_850583411531230682[47] = 1; + out_850583411531230682[48] = 0; + out_850583411531230682[49] = 0; + out_850583411531230682[50] = 0; + out_850583411531230682[51] = 0; + out_850583411531230682[52] = 0; + out_850583411531230682[53] = 0; } -void h_10(double *state, double *unused, double *out_8540054287512262719) { - out_8540054287512262719[0] = 9.8100000000000005*sin(state[1]) - state[4]*state[8] + state[5]*state[7] + state[12] + state[15]; - out_8540054287512262719[1] = -9.8100000000000005*sin(state[0])*cos(state[1]) + state[3]*state[8] - state[5]*state[6] + state[13] + state[16]; - out_8540054287512262719[2] = -9.8100000000000005*cos(state[0])*cos(state[1]) - state[3]*state[7] + state[4]*state[6] + state[14] + state[17]; +void h_10(double *state, double *unused, double *out_3641708848879017741) { + out_3641708848879017741[0] = 9.8100000000000005*sin(state[1]) - state[4]*state[8] + state[5]*state[7] + state[12] + state[15]; + out_3641708848879017741[1] = -9.8100000000000005*sin(state[0])*cos(state[1]) + state[3]*state[8] - state[5]*state[6] + state[13] + state[16]; + out_3641708848879017741[2] = -9.8100000000000005*cos(state[0])*cos(state[1]) - state[3]*state[7] + state[4]*state[6] + state[14] + state[17]; } -void H_10(double *state, double *unused, double *out_5231659216258162963) { - out_5231659216258162963[0] = 0; - out_5231659216258162963[1] = 9.8100000000000005*cos(state[1]); - out_5231659216258162963[2] = 0; - out_5231659216258162963[3] = 0; - out_5231659216258162963[4] = -state[8]; - out_5231659216258162963[5] = state[7]; - out_5231659216258162963[6] = 0; - out_5231659216258162963[7] = state[5]; - out_5231659216258162963[8] = -state[4]; - out_5231659216258162963[9] = 0; - out_5231659216258162963[10] = 0; - out_5231659216258162963[11] = 0; - out_5231659216258162963[12] = 1; - out_5231659216258162963[13] = 0; - out_5231659216258162963[14] = 0; - out_5231659216258162963[15] = 1; - out_5231659216258162963[16] = 0; - out_5231659216258162963[17] = 0; - out_5231659216258162963[18] = -9.8100000000000005*cos(state[0])*cos(state[1]); - out_5231659216258162963[19] = 9.8100000000000005*sin(state[0])*sin(state[1]); - out_5231659216258162963[20] = 0; - out_5231659216258162963[21] = state[8]; - out_5231659216258162963[22] = 0; - out_5231659216258162963[23] = -state[6]; - out_5231659216258162963[24] = -state[5]; - out_5231659216258162963[25] = 0; - out_5231659216258162963[26] = state[3]; - out_5231659216258162963[27] = 0; - out_5231659216258162963[28] = 0; - out_5231659216258162963[29] = 0; - out_5231659216258162963[30] = 0; - out_5231659216258162963[31] = 1; - out_5231659216258162963[32] = 0; - out_5231659216258162963[33] = 0; - out_5231659216258162963[34] = 1; - out_5231659216258162963[35] = 0; - out_5231659216258162963[36] = 9.8100000000000005*sin(state[0])*cos(state[1]); - out_5231659216258162963[37] = 9.8100000000000005*sin(state[1])*cos(state[0]); - out_5231659216258162963[38] = 0; - out_5231659216258162963[39] = -state[7]; - out_5231659216258162963[40] = state[6]; - out_5231659216258162963[41] = 0; - out_5231659216258162963[42] = state[4]; - out_5231659216258162963[43] = -state[3]; - out_5231659216258162963[44] = 0; - out_5231659216258162963[45] = 0; - out_5231659216258162963[46] = 0; - out_5231659216258162963[47] = 0; - out_5231659216258162963[48] = 0; - out_5231659216258162963[49] = 0; - out_5231659216258162963[50] = 1; - out_5231659216258162963[51] = 0; - out_5231659216258162963[52] = 0; - out_5231659216258162963[53] = 1; +void H_10(double *state, double *unused, double *out_7494820718027871329) { + out_7494820718027871329[0] = 0; + out_7494820718027871329[1] = 9.8100000000000005*cos(state[1]); + out_7494820718027871329[2] = 0; + out_7494820718027871329[3] = 0; + out_7494820718027871329[4] = -state[8]; + out_7494820718027871329[5] = state[7]; + out_7494820718027871329[6] = 0; + out_7494820718027871329[7] = state[5]; + out_7494820718027871329[8] = -state[4]; + out_7494820718027871329[9] = 0; + out_7494820718027871329[10] = 0; + out_7494820718027871329[11] = 0; + out_7494820718027871329[12] = 1; + out_7494820718027871329[13] = 0; + out_7494820718027871329[14] = 0; + out_7494820718027871329[15] = 1; + out_7494820718027871329[16] = 0; + out_7494820718027871329[17] = 0; + out_7494820718027871329[18] = -9.8100000000000005*cos(state[0])*cos(state[1]); + out_7494820718027871329[19] = 9.8100000000000005*sin(state[0])*sin(state[1]); + out_7494820718027871329[20] = 0; + out_7494820718027871329[21] = state[8]; + out_7494820718027871329[22] = 0; + out_7494820718027871329[23] = -state[6]; + out_7494820718027871329[24] = -state[5]; + out_7494820718027871329[25] = 0; + out_7494820718027871329[26] = state[3]; + out_7494820718027871329[27] = 0; + out_7494820718027871329[28] = 0; + out_7494820718027871329[29] = 0; + out_7494820718027871329[30] = 0; + out_7494820718027871329[31] = 1; + out_7494820718027871329[32] = 0; + out_7494820718027871329[33] = 0; + out_7494820718027871329[34] = 1; + out_7494820718027871329[35] = 0; + out_7494820718027871329[36] = 9.8100000000000005*sin(state[0])*cos(state[1]); + out_7494820718027871329[37] = 9.8100000000000005*sin(state[1])*cos(state[0]); + out_7494820718027871329[38] = 0; + out_7494820718027871329[39] = -state[7]; + out_7494820718027871329[40] = state[6]; + out_7494820718027871329[41] = 0; + out_7494820718027871329[42] = state[4]; + out_7494820718027871329[43] = -state[3]; + out_7494820718027871329[44] = 0; + out_7494820718027871329[45] = 0; + out_7494820718027871329[46] = 0; + out_7494820718027871329[47] = 0; + out_7494820718027871329[48] = 0; + out_7494820718027871329[49] = 0; + out_7494820718027871329[50] = 1; + out_7494820718027871329[51] = 0; + out_7494820718027871329[52] = 0; + out_7494820718027871329[53] = 1; } -void h_13(double *state, double *unused, double *out_7953441679753433349) { - out_7953441679753433349[0] = state[3]; - out_7953441679753433349[1] = state[4]; - out_7953441679753433349[2] = state[5]; +void h_13(double *state, double *unused, double *out_515642654693887905) { + out_515642654693887905[0] = state[3]; + out_515642654693887905[1] = state[4]; + out_515642654693887905[2] = state[5]; } -void H_13(double *state, double *unused, double *out_207197482328334723) { - out_207197482328334723[0] = 0; - out_207197482328334723[1] = 0; - out_207197482328334723[2] = 0; - out_207197482328334723[3] = 1; - out_207197482328334723[4] = 0; - out_207197482328334723[5] = 0; - out_207197482328334723[6] = 0; - out_207197482328334723[7] = 0; - out_207197482328334723[8] = 0; - out_207197482328334723[9] = 0; - out_207197482328334723[10] = 0; - out_207197482328334723[11] = 0; - out_207197482328334723[12] = 0; - out_207197482328334723[13] = 0; - out_207197482328334723[14] = 0; - out_207197482328334723[15] = 0; - out_207197482328334723[16] = 0; - out_207197482328334723[17] = 0; - out_207197482328334723[18] = 0; - out_207197482328334723[19] = 0; - out_207197482328334723[20] = 0; - out_207197482328334723[21] = 0; - out_207197482328334723[22] = 1; - out_207197482328334723[23] = 0; - out_207197482328334723[24] = 0; - out_207197482328334723[25] = 0; - out_207197482328334723[26] = 0; - out_207197482328334723[27] = 0; - out_207197482328334723[28] = 0; - out_207197482328334723[29] = 0; - out_207197482328334723[30] = 0; - out_207197482328334723[31] = 0; - out_207197482328334723[32] = 0; - out_207197482328334723[33] = 0; - out_207197482328334723[34] = 0; - out_207197482328334723[35] = 0; - out_207197482328334723[36] = 0; - out_207197482328334723[37] = 0; - out_207197482328334723[38] = 0; - out_207197482328334723[39] = 0; - out_207197482328334723[40] = 0; - out_207197482328334723[41] = 1; - out_207197482328334723[42] = 0; - out_207197482328334723[43] = 0; - out_207197482328334723[44] = 0; - out_207197482328334723[45] = 0; - out_207197482328334723[46] = 0; - out_207197482328334723[47] = 0; - out_207197482328334723[48] = 0; - out_207197482328334723[49] = 0; - out_207197482328334723[50] = 0; - out_207197482328334723[51] = 0; - out_207197482328334723[52] = 0; - out_207197482328334723[53] = 0; +void H_13(double *state, double *unused, double *out_4062857236863563483) { + out_4062857236863563483[0] = 0; + out_4062857236863563483[1] = 0; + out_4062857236863563483[2] = 0; + out_4062857236863563483[3] = 1; + out_4062857236863563483[4] = 0; + out_4062857236863563483[5] = 0; + out_4062857236863563483[6] = 0; + out_4062857236863563483[7] = 0; + out_4062857236863563483[8] = 0; + out_4062857236863563483[9] = 0; + out_4062857236863563483[10] = 0; + out_4062857236863563483[11] = 0; + out_4062857236863563483[12] = 0; + out_4062857236863563483[13] = 0; + out_4062857236863563483[14] = 0; + out_4062857236863563483[15] = 0; + out_4062857236863563483[16] = 0; + out_4062857236863563483[17] = 0; + out_4062857236863563483[18] = 0; + out_4062857236863563483[19] = 0; + out_4062857236863563483[20] = 0; + out_4062857236863563483[21] = 0; + out_4062857236863563483[22] = 1; + out_4062857236863563483[23] = 0; + out_4062857236863563483[24] = 0; + out_4062857236863563483[25] = 0; + out_4062857236863563483[26] = 0; + out_4062857236863563483[27] = 0; + out_4062857236863563483[28] = 0; + out_4062857236863563483[29] = 0; + out_4062857236863563483[30] = 0; + out_4062857236863563483[31] = 0; + out_4062857236863563483[32] = 0; + out_4062857236863563483[33] = 0; + out_4062857236863563483[34] = 0; + out_4062857236863563483[35] = 0; + out_4062857236863563483[36] = 0; + out_4062857236863563483[37] = 0; + out_4062857236863563483[38] = 0; + out_4062857236863563483[39] = 0; + out_4062857236863563483[40] = 0; + out_4062857236863563483[41] = 1; + out_4062857236863563483[42] = 0; + out_4062857236863563483[43] = 0; + out_4062857236863563483[44] = 0; + out_4062857236863563483[45] = 0; + out_4062857236863563483[46] = 0; + out_4062857236863563483[47] = 0; + out_4062857236863563483[48] = 0; + out_4062857236863563483[49] = 0; + out_4062857236863563483[50] = 0; + out_4062857236863563483[51] = 0; + out_4062857236863563483[52] = 0; + out_4062857236863563483[53] = 0; } -void h_14(double *state, double *unused, double *out_8785755176393893631) { - out_8785755176393893631[0] = state[6]; - out_8785755176393893631[1] = state[7]; - out_8785755176393893631[2] = state[8]; +void h_14(double *state, double *unused, double *out_1617663395634793849) { + out_1617663395634793849[0] = state[6]; + out_1617663395634793849[1] = state[7]; + out_1617663395634793849[2] = state[8]; } -void H_14(double *state, double *unused, double *out_543769548678817005) { - out_543769548678817005[0] = 0; - out_543769548678817005[1] = 0; - out_543769548678817005[2] = 0; - out_543769548678817005[3] = 0; - out_543769548678817005[4] = 0; - out_543769548678817005[5] = 0; - out_543769548678817005[6] = 1; - out_543769548678817005[7] = 0; - out_543769548678817005[8] = 0; - out_543769548678817005[9] = 0; - out_543769548678817005[10] = 0; - out_543769548678817005[11] = 0; - out_543769548678817005[12] = 0; - out_543769548678817005[13] = 0; - out_543769548678817005[14] = 0; - out_543769548678817005[15] = 0; - out_543769548678817005[16] = 0; - out_543769548678817005[17] = 0; - out_543769548678817005[18] = 0; - out_543769548678817005[19] = 0; - out_543769548678817005[20] = 0; - out_543769548678817005[21] = 0; - out_543769548678817005[22] = 0; - out_543769548678817005[23] = 0; - out_543769548678817005[24] = 0; - out_543769548678817005[25] = 1; - out_543769548678817005[26] = 0; - out_543769548678817005[27] = 0; - out_543769548678817005[28] = 0; - out_543769548678817005[29] = 0; - out_543769548678817005[30] = 0; - out_543769548678817005[31] = 0; - out_543769548678817005[32] = 0; - out_543769548678817005[33] = 0; - out_543769548678817005[34] = 0; - out_543769548678817005[35] = 0; - out_543769548678817005[36] = 0; - out_543769548678817005[37] = 0; - out_543769548678817005[38] = 0; - out_543769548678817005[39] = 0; - out_543769548678817005[40] = 0; - out_543769548678817005[41] = 0; - out_543769548678817005[42] = 0; - out_543769548678817005[43] = 0; - out_543769548678817005[44] = 1; - out_543769548678817005[45] = 0; - out_543769548678817005[46] = 0; - out_543769548678817005[47] = 0; - out_543769548678817005[48] = 0; - out_543769548678817005[49] = 0; - out_543769548678817005[50] = 0; - out_543769548678817005[51] = 0; - out_543769548678817005[52] = 0; - out_543769548678817005[53] = 0; +void H_14(double *state, double *unused, double *out_4813824267870715211) { + out_4813824267870715211[0] = 0; + out_4813824267870715211[1] = 0; + out_4813824267870715211[2] = 0; + out_4813824267870715211[3] = 0; + out_4813824267870715211[4] = 0; + out_4813824267870715211[5] = 0; + out_4813824267870715211[6] = 1; + out_4813824267870715211[7] = 0; + out_4813824267870715211[8] = 0; + out_4813824267870715211[9] = 0; + out_4813824267870715211[10] = 0; + out_4813824267870715211[11] = 0; + out_4813824267870715211[12] = 0; + out_4813824267870715211[13] = 0; + out_4813824267870715211[14] = 0; + out_4813824267870715211[15] = 0; + out_4813824267870715211[16] = 0; + out_4813824267870715211[17] = 0; + out_4813824267870715211[18] = 0; + out_4813824267870715211[19] = 0; + out_4813824267870715211[20] = 0; + out_4813824267870715211[21] = 0; + out_4813824267870715211[22] = 0; + out_4813824267870715211[23] = 0; + out_4813824267870715211[24] = 0; + out_4813824267870715211[25] = 1; + out_4813824267870715211[26] = 0; + out_4813824267870715211[27] = 0; + out_4813824267870715211[28] = 0; + out_4813824267870715211[29] = 0; + out_4813824267870715211[30] = 0; + out_4813824267870715211[31] = 0; + out_4813824267870715211[32] = 0; + out_4813824267870715211[33] = 0; + out_4813824267870715211[34] = 0; + out_4813824267870715211[35] = 0; + out_4813824267870715211[36] = 0; + out_4813824267870715211[37] = 0; + out_4813824267870715211[38] = 0; + out_4813824267870715211[39] = 0; + out_4813824267870715211[40] = 0; + out_4813824267870715211[41] = 0; + out_4813824267870715211[42] = 0; + out_4813824267870715211[43] = 0; + out_4813824267870715211[44] = 1; + out_4813824267870715211[45] = 0; + out_4813824267870715211[46] = 0; + out_4813824267870715211[47] = 0; + out_4813824267870715211[48] = 0; + out_4813824267870715211[49] = 0; + out_4813824267870715211[50] = 0; + out_4813824267870715211[51] = 0; + out_4813824267870715211[52] = 0; + out_4813824267870715211[53] = 0; } #include #include @@ -1113,44 +1113,44 @@ void pose_update_13(double *in_x, double *in_P, double *in_z, double *in_R, doub void pose_update_14(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) { update<3, 3, 0>(in_x, in_P, h_14, H_14, NULL, in_z, in_R, in_ea, MAHA_THRESH_14); } -void pose_err_fun(double *nom_x, double *delta_x, double *out_6497612872484174174) { - err_fun(nom_x, delta_x, out_6497612872484174174); +void pose_err_fun(double *nom_x, double *delta_x, double *out_812796242528121648) { + err_fun(nom_x, delta_x, out_812796242528121648); } -void pose_inv_err_fun(double *nom_x, double *true_x, double *out_1975580934350294204) { - inv_err_fun(nom_x, true_x, out_1975580934350294204); +void pose_inv_err_fun(double *nom_x, double *true_x, double *out_2630998712382937796) { + inv_err_fun(nom_x, true_x, out_2630998712382937796); } -void pose_H_mod_fun(double *state, double *out_4617418789543565628) { - H_mod_fun(state, out_4617418789543565628); +void pose_H_mod_fun(double *state, double *out_8952125250503643232) { + H_mod_fun(state, out_8952125250503643232); } -void pose_f_fun(double *state, double dt, double *out_9094503671864348345) { - f_fun(state, dt, out_9094503671864348345); +void pose_f_fun(double *state, double dt, double *out_3519678704568830866) { + f_fun(state, dt, out_3519678704568830866); } -void pose_F_fun(double *state, double dt, double *out_1312959600226932432) { - F_fun(state, dt, out_1312959600226932432); +void pose_F_fun(double *state, double dt, double *out_6750093296288889328) { + F_fun(state, dt, out_6750093296288889328); } -void pose_h_4(double *state, double *unused, double *out_6400948089178504221) { - h_4(state, unused, out_6400948089178504221); +void pose_h_4(double *state, double *unused, double *out_1078897140345555822) { + h_4(state, unused, out_1078897140345555822); } -void pose_H_4(double *state, double *unused, double *out_3419471307660667524) { - H_4(state, unused, out_3419471307660667524); +void pose_H_4(double *state, double *unused, double *out_850583411531230682) { + H_4(state, unused, out_850583411531230682); } -void pose_h_10(double *state, double *unused, double *out_8540054287512262719) { - h_10(state, unused, out_8540054287512262719); +void pose_h_10(double *state, double *unused, double *out_3641708848879017741) { + h_10(state, unused, out_3641708848879017741); } -void pose_H_10(double *state, double *unused, double *out_5231659216258162963) { - H_10(state, unused, out_5231659216258162963); +void pose_H_10(double *state, double *unused, double *out_7494820718027871329) { + H_10(state, unused, out_7494820718027871329); } -void pose_h_13(double *state, double *unused, double *out_7953441679753433349) { - h_13(state, unused, out_7953441679753433349); +void pose_h_13(double *state, double *unused, double *out_515642654693887905) { + h_13(state, unused, out_515642654693887905); } -void pose_H_13(double *state, double *unused, double *out_207197482328334723) { - H_13(state, unused, out_207197482328334723); +void pose_H_13(double *state, double *unused, double *out_4062857236863563483) { + H_13(state, unused, out_4062857236863563483); } -void pose_h_14(double *state, double *unused, double *out_8785755176393893631) { - h_14(state, unused, out_8785755176393893631); +void pose_h_14(double *state, double *unused, double *out_1617663395634793849) { + h_14(state, unused, out_1617663395634793849); } -void pose_H_14(double *state, double *unused, double *out_543769548678817005) { - H_14(state, unused, out_543769548678817005); +void pose_H_14(double *state, double *unused, double *out_4813824267870715211) { + H_14(state, unused, out_4813824267870715211); } void pose_predict(double *in_x, double *in_P, double *in_Q, double dt) { predict(in_x, in_P, in_Q, dt); diff --git a/selfdrive/locationd/models/generated/pose.h b/selfdrive/locationd/models/generated/pose.h index e7632f322..556e33ecf 100644 --- a/selfdrive/locationd/models/generated/pose.h +++ b/selfdrive/locationd/models/generated/pose.h @@ -5,18 +5,18 @@ void pose_update_4(double *in_x, double *in_P, double *in_z, double *in_R, doubl void pose_update_10(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea); void pose_update_13(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea); void pose_update_14(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea); -void pose_err_fun(double *nom_x, double *delta_x, double *out_6497612872484174174); -void pose_inv_err_fun(double *nom_x, double *true_x, double *out_1975580934350294204); -void pose_H_mod_fun(double *state, double *out_4617418789543565628); -void pose_f_fun(double *state, double dt, double *out_9094503671864348345); -void pose_F_fun(double *state, double dt, double *out_1312959600226932432); -void pose_h_4(double *state, double *unused, double *out_6400948089178504221); -void pose_H_4(double *state, double *unused, double *out_3419471307660667524); -void pose_h_10(double *state, double *unused, double *out_8540054287512262719); -void pose_H_10(double *state, double *unused, double *out_5231659216258162963); -void pose_h_13(double *state, double *unused, double *out_7953441679753433349); -void pose_H_13(double *state, double *unused, double *out_207197482328334723); -void pose_h_14(double *state, double *unused, double *out_8785755176393893631); -void pose_H_14(double *state, double *unused, double *out_543769548678817005); +void pose_err_fun(double *nom_x, double *delta_x, double *out_812796242528121648); +void pose_inv_err_fun(double *nom_x, double *true_x, double *out_2630998712382937796); +void pose_H_mod_fun(double *state, double *out_8952125250503643232); +void pose_f_fun(double *state, double dt, double *out_3519678704568830866); +void pose_F_fun(double *state, double dt, double *out_6750093296288889328); +void pose_h_4(double *state, double *unused, double *out_1078897140345555822); +void pose_H_4(double *state, double *unused, double *out_850583411531230682); +void pose_h_10(double *state, double *unused, double *out_3641708848879017741); +void pose_H_10(double *state, double *unused, double *out_7494820718027871329); +void pose_h_13(double *state, double *unused, double *out_515642654693887905); +void pose_H_13(double *state, double *unused, double *out_4062857236863563483); +void pose_h_14(double *state, double *unused, double *out_1617663395634793849); +void pose_H_14(double *state, double *unused, double *out_4813824267870715211); void pose_predict(double *in_x, double *in_P, double *in_Q, double dt); } \ No newline at end of file diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index 77365b91f..819c2bb23 100644 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -125,6 +125,7 @@ class SelfdriveD: self.last_functional_fan_frame = 0 self.events_prev = [] self.logged_comm_issue = None + self.logged_locationd_issue = None self.not_running_prev = None self.experimental_mode = False self.safe_mode = self.params.get_bool("SafeMode") @@ -161,7 +162,6 @@ class SelfdriveD: self.cancel_pressed_previously = False self.distance_pressed_previously = False - self.display_timer = 0 self.last_below_steer_speed_alert_time = -float("inf") self.last_steer_saturated_alert_time = -float("inf") @@ -172,6 +172,22 @@ class SelfdriveD: self.FPCP = messaging.log_from_bytes(self.params.get("StarPilotCarParams", block=True), custom.StarPilotCarParams) + def _service_diagnostics(self, services: list[str]) -> dict[str, dict[str, object]]: + diagnostics: dict[str, dict[str, object]] = {} + for service in services: + if service not in self.sm.services: + continue + + recv_age_ms = round(max(0.0, (self.sm.frame - self.sm.recv_frame[service]) * DT_CTRL * 1000.0), 1) + diagnostics[service] = { + "valid": self.sm.valid[service], + "alive": self.sm.alive[service], + "freq_ok": self.sm.freq_ok[service], + "recv_age_ms": recv_age_ms, + } + + return diagnostics + def update_events(self, CS): """Compute onroadEvents from carState""" @@ -434,7 +450,22 @@ class SelfdriveD: 'not_freq_ok': [s for s, freq_ok in self.sm.freq_ok.items() if not freq_ok], } if logs != self.logged_comm_issue: - cloudlog.event("commIssue", error=True, **logs) + interesting_services = sorted(set( + logs['invalid'] + + logs['not_alive'] + + logs['not_freq_ok'] + + ['liveCalibration', 'livePose', 'liveParameters', 'radarState', 'driverAssistance', 'longitudinalPlan'] + )) + cloudlog.event( + "commIssue", + error=True, + **logs, + service_diagnostics=self._service_diagnostics(interesting_services), + nav_destination_active=self.params.get("NavDestination") is not None, + navigation_ui=self.params.get_bool("NavigationUI"), + can_timeout=CS.canTimeout, + can_valid=CS.canValid, + ) self.logged_comm_issue = logs else: self.logged_comm_issue = None @@ -444,6 +475,18 @@ class SelfdriveD: self.events.add(EventName.posenetInvalid) if not self.sm['livePose'].inputsOK: self.events.add(EventName.locationdTemporaryError) + locationd_issue = { + "inputs_ok": self.sm['livePose'].inputsOK, + "posenet_ok": self.sm['livePose'].posenetOK, + "live_pose_valid": self.sm.valid['livePose'], + "live_calibration_valid": self.sm.valid['liveCalibration'], + "live_parameters_valid": self.sm.valid['liveParameters'], + } + if locationd_issue != self.logged_locationd_issue: + cloudlog.event("locationdTemporaryError", error=True, **locationd_issue) + self.logged_locationd_issue = locationd_issue + else: + self.logged_locationd_issue = None if not self.sm['liveParameters'].valid and cal_status == log.LiveCalibrationData.Status.calibrated and not TESTING_CLOSET and (not SIMULATION or REPLAY): self.events.add(EventName.paramsdTemporaryError) diff --git a/selfdrive/ui/layouts/settings/starpilot/lateral.py b/selfdrive/ui/layouts/settings/starpilot/lateral.py index a86d5ad98..5c2b43f14 100644 --- a/selfdrive/ui/layouts/settings/starpilot/lateral.py +++ b/selfdrive/ui/layouts/settings/starpilot/lateral.py @@ -242,6 +242,11 @@ class StarPilotLateralLayout(_SettingsPage): get_state=lambda: self._params.get_bool("TurnDesires"), set_state=lambda s: self._params.put_bool("TurnDesires", s), visible=lambda: self._params.get_bool("LateralTune")), + SettingRow("NavDesiresAllowed", "toggle", tr_noop("Use Route Desires"), + subtitle=tr_noop("Allow an active navigation route to request keep-left, keep-right, and low-speed turn desires."), + get_state=lambda: self._params.get_bool("NavDesiresAllowed"), + set_state=lambda s: self._params.put_bool("NavDesiresAllowed", s), + visible=lambda: self._params.get_bool("LateralTune")), SettingRow("NNFF", "toggle", tr_noop("Neural Network Feedforward (NNFF)"), subtitle=tr_noop("Use the full neural-network feedforward steering controller when available."), get_state=lambda: self._params.get_bool("NNFF"), diff --git a/selfdrive/ui/mici/onroad/hud_renderer.py b/selfdrive/ui/mici/onroad/hud_renderer.py index 22d4c93f5..a2b37ab5f 100644 --- a/selfdrive/ui/mici/onroad/hud_renderer.py +++ b/selfdrive/ui/mici/onroad/hud_renderer.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from openpilot.common.constants import CV from openpilot.selfdrive.ui.mici.onroad.torque_bar import TorqueBar from openpilot.selfdrive.ui.mici.onroad.speed_limit_utils import resolve_display_speed_limit_ms +from openpilot.selfdrive.ui.onroad.starpilot.navigation_card import NavigationCardRenderer from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.lib.multilang import tr @@ -139,6 +140,7 @@ class HudRenderer(Widget): self._turn_intent = TurnIntent() self._torque_bar = TorqueBar() + self._navigation_card = NavigationCardRenderer("mici") self._txt_wheel: rl.Texture = gui_app.texture('icons_mici/wheel.png', 50, 50) self._txt_wheel_critical: rl.Texture = gui_app.texture('icons_mici/wheel_critical.png', 50, 50) @@ -254,6 +256,7 @@ class HudRenderer(Widget): if self.is_cruise_set: self._draw_set_speed(self._rect) + self._navigation_card.render(self._rect) self._draw_steering_wheel(self._rect) self._draw_speed_limit_prompt(self._rect) diff --git a/selfdrive/ui/onroad/hud_renderer.py b/selfdrive/ui/onroad/hud_renderer.py index 295053348..307bf9cec 100644 --- a/selfdrive/ui/onroad/hud_renderer.py +++ b/selfdrive/ui/onroad/hud_renderer.py @@ -2,6 +2,7 @@ import pyray as rl from dataclasses import dataclass from openpilot.common.constants import CV from openpilot.selfdrive.ui.onroad.exp_button import ExpButton +from openpilot.selfdrive.ui.onroad.starpilot.navigation_card import NavigationCardRenderer from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.lib.multilang import tr @@ -71,6 +72,7 @@ class HudRenderer(Widget): self._font_medium: rl.Font = gui_app.font(FontWeight.MEDIUM) self._exp_button: ExpButton = ExpButton(UI_CONFIG.button_size, UI_CONFIG.wheel_icon_size) + self._navigation_card = NavigationCardRenderer() def _update_state(self) -> None: """Update HUD state based on car state and controls state.""" @@ -119,6 +121,8 @@ class HudRenderer(Widget): if not ui_state.starpilot_toggles.get("hide_speed", False): self._draw_current_speed(rect) + self._navigation_card.render(rect) + button_x = rect.x + rect.width - UI_CONFIG.border_size - UI_CONFIG.button_size button_y = rect.y + UI_CONFIG.border_size self._exp_button.render(rl.Rectangle(button_x, button_y, UI_CONFIG.button_size, UI_CONFIG.button_size)) diff --git a/selfdrive/ui/onroad/starpilot/navigation_card.py b/selfdrive/ui/onroad/starpilot/navigation_card.py new file mode 100644 index 000000000..e08814e2a --- /dev/null +++ b/selfdrive/ui/onroad/starpilot/navigation_card.py @@ -0,0 +1,384 @@ +from __future__ import annotations + +import math +from pathlib import Path + +import pyray as rl + +from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.system.ui.lib.application import FontWeight, gui_app +from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.widgets import Widget + +ASSETS_PATH = Path(__file__).resolve().parents[4] / "starpilot" / "assets" / "navigation" +FALLBACK_ICON = "direction_turn_straight.png" + + +def _format_distance(distance_m: float, is_metric: bool) -> str: + if is_metric: + if distance_m < 1000: + step = 25 if distance_m < 500 else 50 + return f"{round(distance_m / step) * step} m" + distance_km = distance_m / 1000.0 + return f"{math.floor(distance_km)} km" if distance_km >= 10.0 else f"{distance_km:.1f} km" + + distance_ft = distance_m * 3.28084 + if distance_ft < 1000: + step = 10 if distance_ft <= 100 else 50 + return f"{round(distance_ft / step) * step} ft" + distance_mi = distance_ft / 5280.0 + return f"{math.floor(distance_mi)} mi" if distance_mi >= 10.0 else f"{distance_mi:.1f} mi" + + +def _modifier_suffix(modifier: str) -> str: + suffix_map = { + "left": "left", + "right": "right", + "straight": "straight", + "slightLeft": "slight_left", + "slightRight": "slight_right", + "sharpLeft": "sharp_left", + "sharpRight": "sharp_right", + } + return suffix_map.get(modifier, "") + + +def _normalize_maneuver_type(maneuver_type: str) -> str: + normalized = maneuver_type or "turn" + if normalized == "rotary": + normalized = "roundabout" + elif normalized in ("new name", "continue"): + normalized = "turn" + return normalized.replace(" ", "_") + + +class NavigationCardRenderer(Widget): + def __init__(self, layout_variant: str = "default"): + super().__init__() + self._font_bold = gui_app.font(FontWeight.BOLD) + self._font_medium = gui_app.font(FontWeight.MEDIUM) + self._icons: dict[str, rl.Texture2D] = {} + self._layout_variant = layout_variant + + self._enabled = False + self._valid = False + self._distance = "" + self._primary_text = "" + self._secondary_text = "" + self._maneuver_type = "turn" + self._modifier = "straight" + self._has_next = False + self._next_maneuver_type = "turn" + self._next_modifier = "straight" + + def _icon_filename(self, maneuver_type: str, modifier: str) -> str: + normalized_type = _normalize_maneuver_type(maneuver_type) + if modifier == "uturn": + return "direction_uturn.png" + + suffix = _modifier_suffix(modifier) + candidate = f"direction_{normalized_type}.png" if suffix == "" else f"direction_{normalized_type}_{suffix}.png" + return candidate if (ASSETS_PATH / candidate).exists() else FALLBACK_ICON + + def _get_icon(self, maneuver_type: str, modifier: str): + icon_name = self._icon_filename(maneuver_type, modifier) + if icon_name not in self._icons: + icon_path = ASSETS_PATH / icon_name + if not icon_path.exists(): + icon_path = ASSETS_PATH / FALLBACK_ICON + image = rl.load_image(str(icon_path)) + texture = rl.load_texture_from_image(image) + rl.set_texture_filter(texture, rl.TextureFilter.TEXTURE_FILTER_BILINEAR) + rl.set_texture_wrap(texture, rl.TextureWrap.TEXTURE_WRAP_CLAMP) + rl.unload_image(image) + self._icons[icon_name] = texture + return self._icons[icon_name] + + def _update_state(self) -> None: + sm = ui_state.sm + self._enabled = ui_state.params.get_bool("NavigationUI") + self._valid = False + + if not self._enabled: + return + if sm.recv_frame["navInstruction"] < ui_state.started_frame: + return + if not sm.valid.get("navInstruction", False): + return + + nav_instruction = sm["navInstruction"] + if nav_instruction.maneuverPrimaryText == "": + return + + self._distance = _format_distance(float(nav_instruction.maneuverDistance), ui_state.is_metric) + self._primary_text = nav_instruction.maneuverPrimaryText + self._secondary_text = nav_instruction.maneuverSecondaryText + self._maneuver_type = nav_instruction.maneuverType or "turn" + self._modifier = nav_instruction.maneuverModifier or "straight" + + maneuvers = nav_instruction.allManeuvers + if len(maneuvers) > 1: + self._has_next = True + self._next_maneuver_type = maneuvers[1].type or "turn" + self._next_modifier = maneuvers[1].modifier or "straight" + else: + self._has_next = False + + self._valid = True + + def _wrap_text_lines(self, text: str, max_width: float, font_size: int, max_lines: int = 2) -> tuple[list[str], bool]: + words = text.split() + if not words: + return [], False + + lines: list[str] = [] + current_words: list[str] = [] + word_index = 0 + + while word_index < len(words): + candidate_words = current_words + [words[word_index]] + candidate_line = " ".join(candidate_words) + text_width = measure_text_cached(self._font_bold, candidate_line, font_size).x + if text_width <= max_width or not current_words: + current_words = candidate_words + word_index += 1 + else: + lines.append(" ".join(current_words)) + current_words = [] + if len(lines) >= max_lines: + break + + if current_words and len(lines) < max_lines: + lines.append(" ".join(current_words)) + + truncated = word_index < len(words) + if truncated and lines: + shortened = lines[-1] + candidate = f"{shortened}…" + while shortened and measure_text_cached(self._font_bold, candidate, font_size).x > max_width: + if " " in shortened: + shortened = shortened.rsplit(" ", 1)[0] + else: + shortened = shortened[:-1] + candidate = f"{shortened}…" if shortened else "…" + lines[-1] = candidate + + return lines[:max_lines], truncated + + def _fit_title(self, text: str, max_width: float, preferred_size: int, minimum_size: int) -> tuple[list[str], int]: + font_size = preferred_size + while font_size > minimum_size: + lines, truncated = self._wrap_text_lines(text, max_width, font_size) + widest = max((measure_text_cached(self._font_bold, line, font_size).x for line in lines), default=0) + if not truncated and widest <= max_width: + return lines, font_size + font_size -= 2 + lines, _ = self._wrap_text_lines(text, max_width, minimum_size) + return lines, minimum_size + + def _truncate_text(self, text: str, max_width: float, font_size: int) -> str: + if measure_text_cached(self._font_medium, text, font_size).x <= max_width: + return text + + shortened = text.rstrip() + candidate = f"{shortened}…" + while shortened and measure_text_cached(self._font_medium, candidate, font_size).x > max_width: + shortened = shortened[:-1].rstrip() + candidate = f"{shortened}…" if shortened else "…" + return candidate + + def _draw_wrapped_lines(self, lines: list[str], x: float, y: float, font_size: int) -> None: + if not lines: + return + + text_y = y if len(lines) == 1 else y - (font_size * 0.35) + for index, line in enumerate(lines[:2]): + rl.draw_text_ex(self._font_bold, line, rl.Vector2(x, text_y + index * font_size), font_size, 0, rl.WHITE) + + def _draw_top_aligned_lines(self, lines: list[str], x: float, y: float, font_size: int, line_gap: int = 0) -> None: + for index, line in enumerate(lines[:2]): + line_y = y + index * (font_size + line_gap) + rl.draw_text_ex(self._font_bold, line, rl.Vector2(x, line_y), font_size, 0, rl.WHITE) + + def _render_default(self, rect: rl.Rectangle) -> None: + container_width = min(int(rect.width - 120), 1080) + container_width = max(container_width, 760) + container_height = 225 if rect.width >= 1200 else 195 + container_x = int(rect.x + (rect.width - container_width) / 2) + container_y = int(rect.y + 62) + border_radius = 42 if container_height == 225 else 34 + icon_size = 150 if container_height == 225 else 122 + icon_padding = 30 if container_height == 225 else 24 + then_section_width = 180 if container_height == 225 else 144 + then_icon_size = 105 if container_height == 225 else 82 + preferred_font_size = 75 if container_height == 225 else 58 + minimum_font_size = 60 if container_height == 225 else 46 + distance_font_size = 48 if container_height == 225 else 40 + + container = rl.Rectangle(container_x, container_y, container_width, container_height) + rl.draw_rectangle_rounded(container, border_radius / container_height, 10, rl.Color(0, 0, 0, 192)) + + icon_x = container_x + icon_padding + icon_y = container_y + (container_height - icon_size - 38) // 2 + icon = self._get_icon(self._maneuver_type, self._modifier) + dest_rect = rl.Rectangle(icon_x, icon_y, icon_size, icon_size) + rl.draw_texture_pro(icon, rl.Rectangle(0, 0, icon.width, icon.height), dest_rect, rl.Vector2(0, 0), 0, rl.WHITE) + + distance_size = measure_text_cached(self._font_bold, self._distance, distance_font_size) + distance_x = icon_x + (icon_size - distance_size.x) / 2 + distance_y = icon_y + icon_size + 5 + rl.draw_text_ex(self._font_bold, self._distance, rl.Vector2(distance_x, distance_y), distance_font_size, 0, rl.WHITE) + + show_next = self._has_next + text_x = icon_x + icon_size + 53 + right_gutter = icon_padding + (then_section_width if show_next else 0) + text_area_width = container_width - (text_x - container_x) - right_gutter + title_lines, title_font_size = self._fit_title(self._primary_text, text_area_width, preferred_font_size, minimum_font_size) + title_y = container_y + (container_height - title_font_size) / 2 + self._draw_wrapped_lines(title_lines, text_x, title_y, title_font_size) + + if self._secondary_text: + secondary_font_size = 38 if container_height == 225 else 30 + secondary_text = self._truncate_text(self._secondary_text, text_area_width, secondary_font_size) + secondary_y = container_y + container_height - (42 if container_height == 225 else 30) + rl.draw_text_ex( + self._font_medium, + secondary_text, + rl.Vector2(text_x, secondary_y), + secondary_font_size, + 0, + rl.Color(255, 255, 255, 180), + ) + + if not show_next: + return + + divider_x = container_x + container_width - then_section_width - 8 + rl.draw_line_ex( + rl.Vector2(divider_x, container_y + 23), + rl.Vector2(divider_x, container_y + container_height - 23), + 2, + rl.Color(255, 255, 255, 50), + ) + + then_x = divider_x + 15 + then_label = "Then" + then_font_size = 53 if container_height == 225 else 40 + then_size = measure_text_cached(self._font_medium, then_label, then_font_size) + then_label_x = then_x + (then_section_width - 23 - then_size.x) / 2 + rl.draw_text_ex(self._font_medium, then_label, rl.Vector2(then_label_x, container_y + 30), then_font_size, 0, rl.WHITE) + + next_icon = self._get_icon(self._next_maneuver_type, self._next_modifier) + then_icon_x = then_x + (then_section_width - 23 - then_icon_size) / 2 + then_icon_y = container_y + (84 if container_height == 225 else 72) + rl.draw_texture_pro( + next_icon, + rl.Rectangle(0, 0, next_icon.width, next_icon.height), + rl.Rectangle(then_icon_x, then_icon_y, then_icon_size, then_icon_size), + rl.Vector2(0, 0), + 0, + rl.WHITE, + ) + + def _render_mici(self, rect: rl.Rectangle) -> None: + left_safe = 96 + right_margin = 12 + available_width = max(260, int(rect.width - left_safe - right_margin)) + container_width = min(available_width, 420) + container_height = 142 + container_x = int(rect.x + left_safe) + container_y = int(rect.y + 16) + container = rl.Rectangle(container_x, container_y, container_width, container_height) + rl.draw_rectangle_rounded(container, 0.2, 10, rl.Color(7, 11, 18, 228)) + rl.draw_rectangle_rounded_lines_ex(container, 0.2, 10, 2, rl.Color(255, 255, 255, 34)) + + chip_size = 68 + chip_padding = 18 + chip_x = container_x + chip_padding + chip_y = container_y + 16 + chip_rect = rl.Rectangle(chip_x, chip_y, chip_size, chip_size) + rl.draw_rectangle_rounded(chip_rect, 0.34, 10, rl.Color(70, 80, 94, 228)) + + icon = self._get_icon(self._maneuver_type, self._modifier) + icon_size = 48 + icon_x = chip_x + (chip_size - icon_size) / 2 + icon_y = chip_y + (chip_size - icon_size) / 2 + rl.draw_texture_pro( + icon, + rl.Rectangle(0, 0, icon.width, icon.height), + rl.Rectangle(icon_x, icon_y, icon_size, icon_size), + rl.Vector2(0, 0), + 0, + rl.WHITE, + ) + + distance_font_size = 24 + distance_size = measure_text_cached(self._font_bold, self._distance, distance_font_size) + distance_x = chip_x + (chip_size - distance_size.x) / 2 + distance_y = container_y + container_height - 34 + rl.draw_text_ex(self._font_bold, self._distance, rl.Vector2(distance_x, distance_y), distance_font_size, 0, rl.WHITE) + + show_next = self._has_next and available_width >= 660 + next_section_width = 92 if show_next else 0 + text_x = chip_x + chip_size + 18 + text_width = container_width - (text_x - container_x) - 18 - next_section_width + title_lines, title_font_size = self._fit_title(self._primary_text, text_width, 32, 24) + title_top = container_y + (26 if len(title_lines) == 1 else 16) + self._draw_top_aligned_lines(title_lines, text_x, title_top, title_font_size, line_gap=2) + + show_secondary = bool(self._secondary_text) + if show_secondary: + secondary_font_size = 20 + secondary_text = self._truncate_text(self._secondary_text, text_width, secondary_font_size) + rl.draw_text_ex( + self._font_medium, + secondary_text, + rl.Vector2(text_x, container_y + container_height - 40), + secondary_font_size, + 0, + rl.Color(255, 255, 255, 172), + ) + + if not show_next: + return + + divider_x = container_x + container_width - next_section_width + rl.draw_line_ex( + rl.Vector2(divider_x, container_y + 16), + rl.Vector2(divider_x, container_y + container_height - 16), + 2, + rl.Color(255, 255, 255, 38), + ) + + then_label = "Then" + then_font_size = 20 + then_size = measure_text_cached(self._font_medium, then_label, then_font_size) + then_x = divider_x + (next_section_width - then_size.x) / 2 + rl.draw_text_ex(self._font_medium, then_label, rl.Vector2(then_x, container_y + 16), then_font_size, 0, rl.Color(255, 255, 255, 196)) + + next_icon = self._get_icon(self._next_maneuver_type, self._next_modifier) + next_chip_size = 54 + next_chip_x = divider_x + (next_section_width - next_chip_size) / 2 + next_chip_y = container_y + 46 + next_chip_rect = rl.Rectangle(next_chip_x, next_chip_y, next_chip_size, next_chip_size) + rl.draw_rectangle_rounded(next_chip_rect, 0.34, 10, rl.Color(70, 80, 94, 210)) + next_icon_size = 38 + next_icon_x = next_chip_x + (next_chip_size - next_icon_size) / 2 + next_icon_y = next_chip_y + (next_chip_size - next_icon_size) / 2 + rl.draw_texture_pro( + next_icon, + rl.Rectangle(0, 0, next_icon.width, next_icon.height), + rl.Rectangle(next_icon_x, next_icon_y, next_icon_size, next_icon_size), + rl.Vector2(0, 0), + 0, + rl.WHITE, + ) + + def _render(self, rect: rl.Rectangle) -> None: + self._update_state() + if not self._valid: + return + if self._layout_variant == "mici": + self._render_mici(rect) + else: + self._render_default(rect) diff --git a/selfdrive/ui/qt/onroad/hud.cc b/selfdrive/ui/qt/onroad/hud.cc index dbeabac55..76dcb6e6d 100644 --- a/selfdrive/ui/qt/onroad/hud.cc +++ b/selfdrive/ui/qt/onroad/hud.cc @@ -1,5 +1,7 @@ #include "selfdrive/ui/qt/onroad/hud.h" +#include +#include #include #include "selfdrive/ui/qt/util.h" @@ -40,6 +42,41 @@ void HudRenderer::updateState(const UIState &s) { v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; float v_ego = v_ego_cluster_seen && !starpilot_toggles.value("use_wheel_speed").toBool() ? car_state.getVEgoCluster() : car_state.getVEgo(); speed = std::max(0.0f, v_ego * (is_metric ? MS_TO_KPH : MS_TO_MPH)); + + navigation_enabled = params.getBool("NavigationUI"); + navigation_valid = false; + navigation_has_next = false; + nav_primary_text.clear(); + nav_secondary_text.clear(); + nav_distance.clear(); + nav_maneuver_type.clear(); + nav_modifier.clear(); + nav_next_maneuver_type.clear(); + nav_next_modifier.clear(); + + if (!navigation_enabled || sm.rcv_frame("navInstruction") < s.scene.started_frame || + !sm.alive("navInstruction") || !sm.valid("navInstruction")) { + return; + } + + const auto &nav = sm["navInstruction"].getNavInstruction(); + nav_primary_text = QString::fromUtf8(nav.getManeuverPrimaryText().cStr()).trimmed(); + if (nav_primary_text.isEmpty()) { + return; + } + + navigation_valid = true; + nav_secondary_text = QString::fromUtf8(nav.getManeuverSecondaryText().cStr()).trimmed(); + nav_distance = formatNavDistance(nav.getManeuverDistance()); + nav_maneuver_type = QString::fromUtf8(nav.getManeuverType().cStr()).trimmed(); + nav_modifier = QString::fromUtf8(nav.getManeuverModifier().cStr()).trimmed(); + + const auto maneuvers = nav.getAllManeuvers(); + if (maneuvers.size() > 1) { + navigation_has_next = true; + nav_next_maneuver_type = QString::fromUtf8(maneuvers[1].getType().cStr()).trimmed(); + nav_next_modifier = QString::fromUtf8(maneuvers[1].getModifier().cStr()).trimmed(); + } } void HudRenderer::draw(QPainter &p, const QRect &surface_rect) { @@ -61,6 +98,9 @@ void HudRenderer::draw(QPainter &p, const QRect &surface_rect) { if (starpilot_nvg->standstillDuration == 0 && !starpilot_toggles.value("hide_speed").toBool()) { drawCurrentSpeed(p, surface_rect); } + if (navigation_valid) { + drawNavigationCard(p, surface_rect); + } p.restore(); } @@ -134,3 +174,169 @@ void HudRenderer::drawText(QPainter &p, int x, int y, const QString &text, int a p.setPen(QColor(0xff, 0xff, 0xff, alpha)); p.drawText(real_rect.x(), real_rect.bottom(), text); } + +QString HudRenderer::formatNavDistance(float distance_m) const { + if (is_metric) { + if (distance_m < 1000.0f) { + int step = distance_m < 500.0f ? 25 : 50; + return QString("%1 m").arg(qRound(distance_m / step) * step); + } + float km = distance_m / 1000.0f; + return km >= 10.0f ? QString("%1 km").arg(static_cast(std::floor(km))) : QString("%1 km").arg(km, 0, 'f', 1); + } + + float distance_ft = distance_m * METER_TO_FOOT; + if (distance_ft < 1000.0f) { + int step = distance_ft <= 100.0f ? 10 : 50; + return QString("%1 ft").arg(qRound(distance_ft / step) * step); + } + + float miles = distance_ft / 5280.0f; + return miles >= 10.0f ? QString("%1 mi").arg(static_cast(std::floor(miles))) : QString("%1 mi").arg(miles, 0, 'f', 1); +} + +QString HudRenderer::navigationIconFilename(const QString &maneuver_type, const QString &modifier) const { + QString normalized_type = maneuver_type.isEmpty() ? "turn" : maneuver_type; + if (normalized_type == "rotary") { + normalized_type = "roundabout"; + } else if (normalized_type == "new name" || normalized_type == "continue") { + normalized_type = "turn"; + } + + if (modifier == "uturn") { + return "direction_uturn.png"; + } + + static const QHash suffixes = { + {"left", "left"}, + {"right", "right"}, + {"straight", "straight"}, + {"slightLeft", "slight_left"}, + {"slightRight", "slight_right"}, + {"sharpLeft", "sharp_left"}, + {"sharpRight", "sharp_right"}, + }; + + normalized_type.replace(" ", "_"); + const QString suffix = suffixes.value(modifier, ""); + const QString candidate = suffix.isEmpty() ? QString("direction_%1.png").arg(normalized_type) + : QString("direction_%1_%2.png").arg(normalized_type, suffix); + const QString candidate_path = QString("../../starpilot/assets/navigation/%1").arg(candidate); + return QFileInfo::exists(candidate_path) ? candidate : "direction_turn_straight.png"; +} + +QPixmap HudRenderer::getNavigationIcon(const QString &maneuver_type, const QString &modifier, int size) { + const QString icon_name = navigationIconFilename(maneuver_type, modifier); + const QString cache_key = QString("%1|%2").arg(icon_name).arg(size); + if (!nav_icon_cache.contains(cache_key)) { + nav_icon_cache.insert(cache_key, loadPixmap(QString("../../starpilot/assets/navigation/%1").arg(icon_name), QSize(size, size))); + } + return nav_icon_cache.value(cache_key); +} + +QStringList HudRenderer::wrapNavigationText(int max_width, int font_size, const QString &text) const { + QStringList words = text.split(' ', QString::SkipEmptyParts); + QStringList lines; + QString current_line; + const QFontMetrics metrics(InterFont(font_size, QFont::Bold)); + + for (const QString &word : words) { + QString test_line = current_line.isEmpty() ? word : current_line + " " + word; + if (metrics.horizontalAdvance(test_line) <= max_width) { + current_line = test_line; + } else { + if (!current_line.isEmpty()) { + lines.append(current_line); + } + current_line = word; + if (lines.size() >= 2) { + break; + } + } + } + + if (!current_line.isEmpty() && lines.size() < 2) { + lines.append(current_line); + } + return lines; +} + +void HudRenderer::drawNavigationCard(QPainter &p, const QRect &surface_rect) { + const int container_width = std::clamp(surface_rect.width() - 120, 760, 1080); + const int container_height = surface_rect.width() >= 1200 ? 238 : 206; + const int container_x = (surface_rect.width() - container_width) / 2; + const int container_y = surface_rect.width() >= 1200 ? 332 : 298; + const int border_radius = container_height == 238 ? 42 : 34; + const int icon_size = container_height == 238 ? 150 : 122; + const int icon_padding = container_height == 238 ? 30 : 24; + const int then_section_width = container_height == 238 ? 180 : 144; + const int then_icon_size = container_height == 238 ? 105 : 82; + const int title_font_size = container_height == 238 ? 75 : 58; + const int secondary_font_size = container_height == 238 ? 34 : 28; + const int distance_font_size = container_height == 238 ? 48 : 40; + const int title_top_padding = container_height == 238 ? 10 : 10; + const int title_line_spacing = container_height == 238 ? 68 : 56; + const int secondary_bottom_padding = container_height == 238 ? 24 : 20; + const int secondary_gap = container_height == 238 ? 10 : 8; + + QRect container(container_x, container_y, container_width, container_height); + p.setPen(Qt::NoPen); + p.setBrush(QColor(0, 0, 0, 180)); + p.drawRoundedRect(container, border_radius, border_radius); + + const int icon_x = container_x + icon_padding; + const int icon_y = container_y + title_top_padding + 4; + const QPixmap icon = getNavigationIcon(nav_maneuver_type, nav_modifier, icon_size); + p.drawPixmap(icon_x, icon_y, icon); + + p.setFont(InterFont(distance_font_size, QFont::Bold)); + p.setPen(Qt::white); + const int distance_width = p.fontMetrics().horizontalAdvance(nav_distance); + p.drawText(icon_x + (icon_size - distance_width) / 2, container_y + container_height - 18, nav_distance); + + const int text_x = icon_x + icon_size + 53; + const int right_gutter = icon_padding + (navigation_has_next ? then_section_width : 0); + const int text_width = container_width - (text_x - container_x) - right_gutter; + const QStringList title_lines = wrapNavigationText(text_width, title_font_size, nav_primary_text); + const QFont title_font = InterFont(title_font_size, QFont::Bold); + const QFontMetrics title_metrics(title_font); + const int title_baseline = container_y + title_top_padding + title_metrics.ascent(); + + p.setFont(title_font); + p.setPen(Qt::white); + for (int index = 0; index < title_lines.size() && index < 2; ++index) { + p.drawText(text_x, title_baseline + index * title_line_spacing, title_lines[index]); + } + + if (!nav_secondary_text.isEmpty()) { + const QFont secondary_font = InterFont(secondary_font_size, QFont::Medium); + const QFontMetrics secondary_metrics(secondary_font); + const int title_bottom = title_baseline + (std::max(title_lines.size(), 1) - 1) * title_line_spacing + title_metrics.descent(); + const int secondary_max_baseline = container_y + container_height - secondary_bottom_padding - secondary_metrics.descent(); + const int secondary_preferred_baseline = title_bottom + secondary_gap + secondary_metrics.ascent(); + const int secondary_baseline = std::min(secondary_preferred_baseline, secondary_max_baseline); + p.setFont(secondary_font); + p.setPen(QColor(255, 255, 255, 180)); + p.drawText(text_x, secondary_baseline, nav_secondary_text); + } + + if (!navigation_has_next) { + return; + } + + const int divider_x = container_x + container_width - then_section_width - 8; + p.setPen(QPen(QColor(255, 255, 255, 50), 2)); + p.drawLine(divider_x, container_y + 23, divider_x, container_y + container_height - 23); + + p.setFont(InterFont(container_height == 225 ? 53 : 40, QFont::Medium)); + p.setPen(Qt::white); + const QString then_label = tr("Then"); + const int then_x = divider_x + 15; + const int then_label_width = p.fontMetrics().horizontalAdvance(then_label); + p.drawText(then_x + (then_section_width - 23 - then_label_width) / 2, container_y + (container_height == 238 ? 66 : 60), then_label); + + const QPixmap next_icon = getNavigationIcon(nav_next_maneuver_type, nav_next_modifier, then_icon_size); + const int then_icon_x = then_x + (then_section_width - 23 - then_icon_size) / 2; + const int then_icon_y = container_y + (container_height == 238 ? 96 : 78); + p.drawPixmap(then_icon_x, then_icon_y, next_icon); +} diff --git a/selfdrive/ui/qt/onroad/hud.h b/selfdrive/ui/qt/onroad/hud.h index f7c6a465c..c5ea2539e 100644 --- a/selfdrive/ui/qt/onroad/hud.h +++ b/selfdrive/ui/qt/onroad/hud.h @@ -1,6 +1,8 @@ #pragma once +#include #include +#include #include "selfdrive/ui/ui.h" #include "starpilot/ui/qt/onroad/starpilot_annotated_camera.h" @@ -20,7 +22,12 @@ public: private: void drawSetSpeed(QPainter &p, const QRect &surface_rect); void drawCurrentSpeed(QPainter &p, const QRect &surface_rect); + void drawNavigationCard(QPainter &p, const QRect &surface_rect); void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); + QStringList wrapNavigationText(int max_width, int font_size, const QString &text) const; + QString formatNavDistance(float distance_m) const; + QString navigationIconFilename(const QString &maneuver_type, const QString &modifier) const; + QPixmap getNavigationIcon(const QString &maneuver_type, const QString &modifier, int size); float speed = 0; float set_speed = 0; @@ -28,5 +35,17 @@ private: bool is_cruise_available = true; bool is_metric = false; bool v_ego_cluster_seen = false; + bool navigation_enabled = false; + bool navigation_valid = false; + bool navigation_has_next = false; int status = STATUS_DISENGAGED; + QString nav_distance; + QString nav_primary_text; + QString nav_secondary_text; + QString nav_maneuver_type; + QString nav_modifier; + QString nav_next_maneuver_type; + QString nav_next_modifier; + QHash nav_icon_cache; + Params params; }; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 3279e77d5..d8d1b547e 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -367,6 +367,7 @@ UIState::UIState(QObject *parent) : QObject(parent) { "modelV2", "controlsState", "liveCalibration", "radarState", "deviceState", "pandaStates", "carParams", "driverMonitoringState", "carState", "driverStateV2", "wideRoadCameraState", "managerState", "selfdriveState", "longitudinalPlan", + "navInstruction", }); prime_state = new PrimeState(this); language = QString::fromStdString(Params().get("LanguageSetting")); diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index 220515bc0..e5512102f 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -54,6 +54,7 @@ class UIState: "longitudinalPlan", "gpsLocationExternal", "mapdOut", + "navInstruction", "carOutput", "carControl", "liveParameters", diff --git a/starpilot/assets/navigation/direction_arrive.png b/starpilot/assets/navigation/direction_arrive.png new file mode 100644 index 0000000000000000000000000000000000000000..733c12909112694fdab3489ba6d21d042c96d4c7 GIT binary patch literal 1246 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 literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_continue.png b/starpilot/assets/navigation/direction_continue.png new file mode 100644 index 0000000000000000000000000000000000000000..a01045ae6a2b586dfc374fb7e34e4adbf78a1180 GIT binary patch literal 1063 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HlU>(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_continue_left.png b/starpilot/assets/navigation/direction_continue_left.png new file mode 100644 index 0000000000000000000000000000000000000000..9a618026f0e00dd044f359e1f3fed8c668c63b6b GIT binary patch literal 1400 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 ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_continue_slight_left.png b/starpilot/assets/navigation/direction_continue_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..08e964dbd6a68a9b82983499adda5a8bc78ac1a9 GIT binary patch literal 1334 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!Hk}t5;vVc=7)I`!8R< z{P^+X7a078fj_9=FVW!t|NrUy|2Tmb$dv^71v9X53y7;4TRV9LM<-0O!S98_ka)FR--p$H*(I&$YN^{laaWA^&#_v<-EeHR2-Khu)uSPdrqs z%R4_kOFgzOFZ@OC|B9V|JNmA*_TRq#A|ZB;P0O1L2X}oatX{Wli_nLn->#`#KM(3} ze;)s$;%&vVZ>m;t+ID&Rfv+pxd;MEuvio=VrUVZT~-`@|9kHuauHf8C3urD;jug$lQ7WE{R8R_ENsB1nK6-!NoyQusn?w$u(EV}!t(|sFPUhBzqmM7|6koqS zQY}vI^yd6|dEf8Y=$ake`Q&BU`Ow73m;*7N3U;qvE;R9TQrm17n`2@BEFI?EdH7Dm z<$IC#gPE^FM1=l3cF4|@*`)Krw&P8?sBwtB+O0QoXB>r?sv7?Yeez$Fxaw_pMA6H= z|1#WlLN=VOmY6u@-rnHVY)70GzWgz1nW>V}A-&`ScVXKhh14R>Bse^mVGt-SN)PFm6r%Y&UJxM@1)+;&yW56O@W<(c9|iO;O!eu1cJ!0T-+CuOctIiHwC5+gYjanl%dH3>VEM%0>FVdQ I&MBb@06s*zH~;_u literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_continue_slight_right.png b/starpilot/assets/navigation/direction_continue_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3e21cae11ed5209a7f63f7352d7ca2c4ef5b0b14 GIT binary patch literal 1347 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HkZOP5}}c=7)I`_G?0 z|M>Ca7a078fj_9=FVW!t|Nrx>eU1VxkShuD3ua*D77$l8ws!Ikj!w=lu5Rj@JbTIN z&ASetxpL?6>mzF(>N7B~lzX~3hE&XXJLl%K#Rfbsk(=NDcKi3=cy@`EtojKy>pAO^ z+`gA4^sQQ$<0;muSv3bA5XEv~P#B&%EZJ^m3=FqQ-iAN!e&YBlp)Dl5e5}nm+IH-1jen!;$a5 z@3uc@z9+1oy=3!gcBc<<<{if$Y8p0Q_ig*_pePe({xY|@WkbbX6_rxOPrE$LzQ-O~ zu_tem&z~h5D(^0MuG(_`wf`QoYPa?FGb&#weElUme`|I(-!;c)kIRzQKaUGN#UQ(G zYUBM^-mkxQPVadwDZ9RR>3qJh_3HPg>My@;{C`o)rPq5KCYigk>k3?2n*QaNjRX6_ z>ytMeGn;#Tv-1Q#tM$(p<|Y`e=XbU)Nr{`!c1q!MRZMVgPMUVMd{GaZxg>C8n@Zg7Hii(G;ZOfLawn{A6u=DZWcQ$4g&p-K2ZSVNL zYqOR8jj9DxugTtdeQr<6`9n4*S3Nd{S*$ zee>ZL_D9=$w}*fF;?5X7A*ffr&(vM^#hB+mTg^sD!a7x>n_{k_-pt7?8iRnZHtx9QDx4?ezPT|?aVIXC2NoT}swG4IXu6yu(Mv32=rps3A+!oPFb_UkTL z_S*S(gv_IxU;n)IeY8h!yZhd_H76?U6XVuTaV_6tFQ#`PZu)Y@Z}n~RPnfUo0pPfKqz{iF@ zEryLD-@W}TCX^j!x|6`|=u=Zz9cA(8(d+$^k0w473)s)_NpOi$F3PaPp!@`z0o4S^2||x zT^5DjkFpmXTNR$}i`7|mL^$(S{`Oc8^#yb9@GouJ+srFsdG*y2ftQ^npRP`_aWdw4 zci4V&mS^cyF2_YqHv$xMRtT7da7b&l@QNO4<4SZEdSrj!r2)uj-LMdwywt-NDQER+ zjqjdhw8~tzvD(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_continue_uturn.png b/starpilot/assets/navigation/direction_continue_uturn.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd1b91777ed8d3c487e188c945383482b219c43 GIT binary patch literal 1780 zcmbW2X*Amj7l#vDB4TMe!Kqq8(GzNE6(!mcX@yBDme84?A#Erv(uP{PF_sQ#TD5dS zsM?Bu#?n$tLfT=dWsDk3YbjE-R5YE^O3)ZHALhL8$M=2C{oUuwJ?DPA_XpBRcXikv z7zhMX_rT+PcKrPBKoxg-L3%K6M>G<_@A!^KMn)DF7bOzO+S=Os`npsqmC0lq|FHQF zTmQ|M|Ap=C?GRf+?amq_rq4-Vkcyg?F3J>bhdJR(p+z#2Qdl{KWx!*8SO4hb%v*6P zhn5clsTg_ST>av?D@Dr%r8e+%2&SYIUL1?DS-+mQ%<#icG!n<(ug-npJD1rYt*-}YqocT$4L$Io!im0?sXPxcqnYyx z<0lcTG-SvJsSEqxV10iv_@cHjkv&FSy3l?mFxnGw@>tj4UZ?p6@|CN^Ed#)O0`rKS ziR(^t3v`!N4l_9VG&E{t7g@EMebe)1Y+!EJx07B~v4Q!)wy%Sf-?b-A^76A}p{?U( z@=YfJTi$C|wfdx35FL@V#K@7e)xjWc_BW6lcyn_#Ay+C|TAXFx{4JR~>FvbO6phu>l*_CVvM>m3I z74R>AIGgaX{ax;?y&mXv$8<-)uY*s?dYONs!C!`tWrH#Jv+5;SHCW1&qO|Mc`>8|E zjedzxNX&>C+&5$GzRTzP*A(t1&L)c3KuXIW;qomOT|6EMX#9GG@Cwh5N;j4dbaM+$ zscgDRx}b=0sR=xQGA@UfbS8GQtilgrbDBUz5{rV^Kj3jF+EsG8y9|Mc-a67@0kJp7 z`W*Uy;vV<*3Tvr*hHh1u+ucP+qnbxp$gEaDTmAq~9g>2>7FP=>ov7^gR{0jgDI6bf zj`--LHyNo}a{gCjbgRV%3u%m!n8){c1|`zNqP7@wRbKl{geCz6t$mUU19?BK65DgM zRF}%>mLWp-LVl9eIsIo$O|!p)&KX6S%kbp=456d0r)hQSnWt$Wp*zRohPbgiH^Rdn z_4&bh0ejkH;MOyE7|kC%RRFGqoqMM#%wT^yhBz>8Ag7+Q^J_o|t zk|pO=g~I*#jvvh4on$xUS!(gtYA*O&|P**T3DzPPegOX$7vnpiAFb3go52@ zp6HJ|rlbySV_vAv&IleKbu{V&uT(S7H4F|&uPvcYp-V!7*P_7sRu8@P{2Me1n9v`& z)vCZt2$2*JhA349v>LBMIaUB1ATcdq1?vD5Xi*|Mr4p$s&Py+t*EB4Y;J{F0h$`1d zBb6-B8=6wJEKi#Jdh|E@#yfG9IgvxS5m|_0M3BcA}Zn_hHs^S7rE@)kjnA z1ZbPTU8jUX6Vl07Qq1&Ap$TUgcgK^p)wfQYwR|cnzaUiS;n&MmsPwg<^ZXu~YsWYB z#@lm#W0@n|S1xlW20v_R)W{5DIg2{M%KvfRZqUx^eZ#oxcL|IDQgWi>0Rg E1z#s(%m4rY literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_depart.png b/starpilot/assets/navigation/direction_depart.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf32c870d5f26dcca6c5e80537cff2c2cc4461b GIT binary patch literal 1234 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3Pvq5^zET!HlY^XH#GfBydc`_G?0 z|M>Ca*RNl{Vc-uc_)9eS|Np=2bS4|1>9Qq3e!&c^+yY{1md@UR(aG6GHBH@w8Q4`}NA5#b!>YG+S=^2(UN`upDeJ^$;DGFY^- zToXm!PUhb+?aHjCiu!Mi7lN|69+tjgPVirQYW~yW#+r{#Yfn%A>H1oE@6+VP-x&*L z277-_O8&%nAt3wnLZjadHv(1{FW+;kN9BsR{TjPVFT1UG^EdEkwdSoclxMKc>eZ95 zdN{#!tJj?BjHbyB@isetcqoKb7Jp_eSP+(V{1#{XhQ81#7g*YhXU-}3x!<5KG%IHB zsm`eNoucb%IW9+}ip+Yj;ZB}JyPAdV@u!Q`Ob%xL{OX#U(R5fZtT0OJRf5>+8BW47 zX{V1Tui#JHc*^V!`|60J$tzbh`>ttfQL~6i5>+udm?*UR&GKIfLaX=qd_SlZ#`&(r z`9$*64}KOcd-SEY^Ve8j{^t4|=m?XrnKwAw_gwt>fy=kx#i=9OCI=O}Lv5UeWfnyo zwFYu_b{i`Isg6*t+ut0^jlP|Hmyx}YWn-7BN#^_O54Hc=zp3k6t8;zw#bnXqjG{mL zc3pUPpjMx6`ZIgyC%Y|ry^nsspSIxliO0)RbAPq1*x0pD_}kX1j@NdJbyhr+K0N)% zo96>`iVxp(P7Ft*ulFl-qXoi>=O>)}`)S_aNy>SnjO5mpwL~ zvM{mC;LkQ!-v0h}?<+gMHJ?gey(w=~dzR%A{QdcVjsMdR>esF-U@ceP9C+6~v-_0L z;~eXk)sj0y=T!v?q%Qq*Vq=Nux(AsqYkym`hy5(gd8r+9@b-zt?~=bBDY_r$Bf3r? z;Yr;0w~~K_UDZx-xF6v#rvz;>b6Ts(aaZ;fFu7f@Q9E4ru1)l8>{gxj&<8zooynhP zY|#%bek&g%t;g@l-K4+)MH6^kx8~~EI@~wCt#xw8m&u#tY|?AjR{CUoUV6o5#XXgb z)U~prH;iZh=nRrrzRuips#l`q!y>N}ooC&H{3c}n>uH;Q%Q3!uqQ_DF3m2E^xF_}( zR`|LIv4?m5?l75?q~tgGrBKD?yoV-#zMuLp^2VZh(too#Pv<6S`NXeY@W5i})c=*I z3v=?^*9spkty13VC*m%jq#|`wChDe0wb}CfIZ{bx-cxeKdT;7H{=9R;sb@jv^FJug zw$Pa0pf~@7$!r1Z`MIr;X41CiVl#90p51hlXK!%GY?*D#S%LZ4vE!_L!-tFyXRZr- Q0gDd?Pgg&ebxsLQ0MYho$N&HU literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_depart_left.png b/starpilot/assets/navigation/direction_depart_left.png new file mode 100644 index 0000000000000000000000000000000000000000..1f8d726911fcb7ad726e80a4fd84d0c5cea33240 GIT binary patch literal 1613 zcmb7^Yd8}M7{|B7thwLPvT7ma(uF!La$D1gGqaZ{lGSIZh=)TZJ)f?Yo42fn8PgZM9#~N%oZSLH+ul z$qtk}{2;uZ5Xf11@ijXz`JKci zlpl={TwzTR%X{Go=Lb}Qp z3#tY4vZ=W^(XL2-Oj``^PF#`yq+3wM6Qht-@ZNF$`n8Nq$U_h6wM~cz2bKLU2wnW8 zE1WIE<6_h7a$A%9GR7~NHJg1u(i=tZUV%ecIRCwdm!$R%&n1D;DQh}`jM zkDQaj6X*Ep{*MyM=yfWP)6rRds%g&0y+Ss@wX-<-%-5)!fBM-=E((hzILP_YM_w3z za@#@QkmXM!i^PoW>PdG9N|xxjBN?+d6YMIO-+gxs?_nrO<`rzIFwbel`%=1zwOHJa zmZ8?H?D{h-%c$k|{WWHD1&+cX0Zr}tP=DBxtk=lSG4RQpP zb+U{l7`qoOVhS7$d+ACp9S^bTG9{S8tsxW;Phq^-$@pC)xL?>!kAtdv6&VxQqTEZYKGYhRUG zQ(Sn@U6+)nXFklA-*4H02(}DsWXd6g*pi#OjTkgYOw0XxMbFs}j%Q~~`sKY)5GCe)ayrjJJI> z`K*bsSHm(JIQU{AQgmbAd#IiP^3;Ni6dvd*wbCFvOwwb|7MuIYO{Ly`_+fFC8$PoD zfJEMg8d-vy836D$kQNDn_57uR-RTGC@sP*^%+zyhz}m(JP&em_Fr7-6TZ=^(*b8k! zg`<82-UBrK{fz$939}eDk3ezMn-Po5zmS3OX7hE&;4!9B^ z_pG*8FGL8~_&@=mWr*qeeobocX`s2`9vngPt?$+*%k8ksc?q>LZ@MY9jyyf0sByRd zERWDxq&8cnM_xzVk*#<5JUtRs6us(gfeX-=iLQ`Xtllpt-6ljBEa_r4;om}*kFeOj zpP4NrcM5Dd$B6TceLk)T*eadTrSC=_um`o6%@DM3r-V*4E7m+uO{TstrlXRH>3zbRj;r z-84wIXdqF^U0APUd6|OPu+h*@lfSB^l48s*|l8osH=N> oV}MhJC0xD#4gztYwKFAof=78%C)3lY;RQ2+n{ literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_depart_right.png b/starpilot/assets/navigation/direction_depart_right.png new file mode 100644 index 0000000000000000000000000000000000000000..f359a685ffa5682a226ec488aa359cfb0fccb7f6 GIT binary patch literal 1538 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 Q0gDd?Pgg&ebxsLQ0MYho$N&HU literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_end_of_road_left.png b/starpilot/assets/navigation/direction_end_of_road_left.png new file mode 100644 index 0000000000000000000000000000000000000000..5c0a24e7cb11c45ce7e676cc81c389229ccd785b GIT binary patch literal 1439 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 literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_flag.png b/starpilot/assets/navigation/direction_flag.png new file mode 100644 index 0000000000000000000000000000000000000000..bad12ec6664679d0d42d7f270d2740a80db95d5e GIT binary patch literal 658 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvECYN(T!HkXM~~jWfB)snm+#-d z|NQy$*RNl{fB*gi1AnoB|NsB5*SvHZs9C5a$S;_IQ$Rx5z|J?Zw61&p#@&Z5+@0|+ zFSZ||P=VonrbeOS@!)~ojZ|Ar=^J1=zJ%quy&FiV@oZqE~o&-^#v zo`Hd$+y5%; zNL0Am=-N1iU5q72K7z;N@Bt?WD>gBvONJXbCQNH&ZTP~orqbi`0jc&9-ZhyXw+~3Q zec@db>GAl0RBH*}8c&bc2c%lQ@U5}*__QIUomo3@ZiuwwU$gDbP`D{w@2c72{ z3FjW3ne%v)CHsuxzA4XTKAo?8qx9Ty#vJ#_NpfPRD{J(hH=g?S=8(gx&E3qJ=hmg3 zXcKbs=FnB#(sF@9MpvUweb0losDBB^b+`TqoIN}1 P(+7j6tDnm{r-UW|YGF%* literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_fork.png b/starpilot/assets/navigation/direction_fork.png new file mode 100644 index 0000000000000000000000000000000000000000..3e0c262e2a2785e2795b9312f60d432e0171cb62 GIT binary patch literal 2015 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 literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_fork_right.png b/starpilot/assets/navigation/direction_fork_right.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3efaabca2cf7a040f0e7188da6503917c338e5 GIT binary patch literal 1841 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 literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_fork_slight_right.png b/starpilot/assets/navigation/direction_fork_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3596a2fbf2945d487ee19e294413603a60a21fb6 GIT binary patch literal 1805 zcmb7_c{Ce{7RF^^+C-BwN+UI7&}yjZVri>P6-6bs zSRPF>)d&^E)KZj6CU$DgjHRNqnx%+5@4fTR={slsncw;D{myspJ?H*;@A~;5RFrg; z004lBrw2S>&wKw}it>B?aXOZ^XP5nuDEB=d8yj0%T3TOU-`w03i^UR&n+S=Ow zA3Oh#^sgh6$%ZD4Z|~g$#|QWX0u+>i+8`rS>r?RW0z$qg#F1`iJ}jm_X=v%}ADWov z3qA;?Bh%pkfP%Rv+y#|LUL&tOuCqLlu9msoX7NwMW?7QMMSmdA%W6E^cLtXY`a9Rc zn`bTCwK~vg`GrtK>29n8#UiM9dOoo&RZPKW>dse2a5R|W4gqH0KeVf(yEaIjzrhPz zXOx(?F$c%i7*^KN@nIt8LPwkuQ>|uB7h=_tP3Ya~LmzlAiWqxdNbGFq7UC{=tRkXd z2k@?_>r>I{fpK-6K^W}Zh|oE(YkhR_Q(SONTIe4N&$ zGgwHJ^d+iO?K@UU{cvm-mY&&LmHTv@mOwY@#?sY<6&CfQ+u+h=q-Lv4TF`2)Gx;O@ z$LRR@66ZQ0)cGJB$Z>MYWe$CkZ`>z>6#{7FpBPU=h4V!Y(ujTKqZwATA)PRk0H#|n z)lL9WMw5;SHVa&9meg!uQU2_n<4(sDb?jgA4yDH0P71 z-6fS+bc)6-T*D1B96LaPs|G}nIcj=s$RianD?10QUc&_Nt+(Z_JV}@syP?sId2=1BI-g(|gmLY;JB-g&! zd`i#Dk=RhcS$eFA+>ljhg+1Hz2a!6%$e_mrmd$%iYplt|u0lPRLhq+6C{*>21^*Fj z!mqo@kf*~0`B#qaVAPdSn&r=8{MVShyfaFblnnK*&qyke{d zkxJA(?{@1n$7^&3n@1Wn?%-#~dB$lWoT%;VjctQY&rtdIX0&38RTskfO)pBv%VbjB z#+D&c_SIX8{VyH?NgsQs!reQPKA$c?bAV~5Q>CvDH}cwim=FSVZW^C;nwTByrjU#y zoqF7u*}wYZ5rU%|@`hXh!85Qsf&wmQ@~*N+N$Cb1<+}{p>De*0e7~rp2@K)=m#ry% z;l(L~Z^l-=3M!K5k#{60N{x~2?{)R)U{vrdm-NaDK2=~#O5`|>o*RrWS+e^L{bV8J z@b*K!il#~_jnPIG=B4ZeEU=%u+EABwKD1ik9WToH<0Tw_SeW-4Crr&OkMz2hJjB0l zww5+DH-+{+W`c35rp2|kCXOs%})B;mvyrjgN*qS zV9VJKN&X4NZ{^Bbx@18EUT5Xmo_&k^iLo0HeE6i<^$n@zPrjg$i&^@a23bQi|E2&WXBmys8&{vYfVj+$)ORUOgZwv34ri5peHTxi{55-A z;Z&HO;7;^YaO2A_!-tbvpg*7Nt-a#dS#N0}$T;G@DP_r6V`$`XOrK8a>hbQ{%Y;0c h*fKrz&=*SiSvEk{C&;49@q2#;;OXuIXSiOt^)FTRxGewx literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_fork_straight.png b/starpilot/assets/navigation/direction_fork_straight.png new file mode 100644 index 0000000000000000000000000000000000000000..86f30ab9b6edec7d892cdf1d7bde9999a85b8d83 GIT binary patch literal 2473 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 Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_invalid_left.png b/starpilot/assets/navigation/direction_invalid_left.png new file mode 100644 index 0000000000000000000000000000000000000000..9a618026f0e00dd044f359e1f3fed8c668c63b6b GIT binary patch literal 1400 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 ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_invalid_slight_left.png b/starpilot/assets/navigation/direction_invalid_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..08e964dbd6a68a9b82983499adda5a8bc78ac1a9 GIT binary patch literal 1334 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!Hk}t5;vVc=7)I`!8R< z{P^+X7a078fj_9=FVW!t|NrUy|2Tmb$dv^71v9X53y7;4TRV9LM<-0O!S98_ka)FR--p$H*(I&$YN^{laaWA^&#_v<-EeHR2-Khu)uSPdrqs z%R4_kOFgzOFZ@OC|B9V|JNmA*_TRq#A|ZB;P0O1L2X}oatX{Wli_nLn->#`#KM(3} ze;)s$;%&vVZ>m;t+ID&Rfv+pxd;MEuvio=VrUVZT~-`@|9kHuauHf8C3urD;jug$lQ7WE{R8R_ENsB1nK6-!NoyQusn?w$u(EV}!t(|sFPUhBzqmM7|6koqS zQY}vI^yd6|dEf8Y=$ake`Q&BU`Ow73m;*7N3U;qvE;R9TQrm17n`2@BEFI?EdH7Dm z<$IC#gPE^FM1=l3cF4|@*`)Krw&P8?sBwtB+O0QoXB>r?sv7?Yeez$Fxaw_pMA6H= z|1#WlLN=VOmY6u@-rnHVY)70GzWgz1nW>V}A-&`ScVXKhh14R>Bse^mVGt-SN)PFm6r%Y&UJxM@1)+;&yW56O@W<(c9|iO;O!eu1cJ!0T-+CuOctIiHwC5+gYjanl%dH3>VEM%0>FVdQ I&MBb@06s*zH~;_u literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_invalid_slight_right.png b/starpilot/assets/navigation/direction_invalid_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3e21cae11ed5209a7f63f7352d7ca2c4ef5b0b14 GIT binary patch literal 1347 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HkZOP5}}c=7)I`_G?0 z|M>Ca7a078fj_9=FVW!t|Nrx>eU1VxkShuD3ua*D77$l8ws!Ikj!w=lu5Rj@JbTIN z&ASetxpL?6>mzF(>N7B~lzX~3hE&XXJLl%K#Rfbsk(=NDcKi3=cy@`EtojKy>pAO^ z+`gA4^sQQ$<0;muSv3bA5XEv~P#B&%EZJ^m3=FqQ-iAN!e&YBlp)Dl5e5}nm+IH-1jen!;$a5 z@3uc@z9+1oy=3!gcBc<<<{if$Y8p0Q_ig*_pePe({xY|@WkbbX6_rxOPrE$LzQ-O~ zu_tem&z~h5D(^0MuG(_`wf`QoYPa?FGb&#weElUme`|I(-!;c)kIRzQKaUGN#UQ(G zYUBM^-mkxQPVadwDZ9RR>3qJh_3HPg>My@;{C`o)rPq5KCYigk>k3?2n*QaNjRX6_ z>ytMeGn;#Tv-1Q#tM$(p<|Y`e=XbU)Nr{`!c1q!MRZMVgPMUVMd{GaZxg>C8n@Zg7Hii(G;ZOfLawn{A6u=DZWcQ$4g&p-K2ZSVNL zYqOR8jj9DxugTtdeQr<6`9n4*S3Nd{S*$ zee>ZL_D9=$w}*fF;?5X7A*ffr&(vM^#hB+mTg^sD!a7x>n_{k_-pt7?8iRnZHtx9QDx4?ezPT|?aVIXC2NoT}swG4IXu6yu(Mv32=rps3A+!oPFb_UkTL z_S*S(gv_IxU;n)IeY8h!yZhd_H76?U6XVuTaV_6tFQ#`PZu)Y@Z}n~RPnfUo0pPfKqz{iF@ zEryLD-@W}TCX^j!x|6`|=u=Zz9cA(8(d+$^k0w473)s)_NpOi$F3PaPp!@`z0o4S^2||x zT^5DjkFpmXTNR$}i`7|mL^$(S{`Oc8^#yb9@GouJ+srFsdG*y2ftQ^npRP`_aWdw4 zci4V&mS^cyF2_YqHv$xMRtT7da7b&l@QNO4<4SZEdSrj!r2)uj-LMdwywt-NDQER+ zjqjdhw8~tzvD(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_invalid_uturn.png b/starpilot/assets/navigation/direction_invalid_uturn.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd1b91777ed8d3c487e188c945383482b219c43 GIT binary patch literal 1780 zcmbW2X*Amj7l#vDB4TMe!Kqq8(GzNE6(!mcX@yBDme84?A#Erv(uP{PF_sQ#TD5dS zsM?Bu#?n$tLfT=dWsDk3YbjE-R5YE^O3)ZHALhL8$M=2C{oUuwJ?DPA_XpBRcXikv z7zhMX_rT+PcKrPBKoxg-L3%K6M>G<_@A!^KMn)DF7bOzO+S=Os`npsqmC0lq|FHQF zTmQ|M|Ap=C?GRf+?amq_rq4-Vkcyg?F3J>bhdJR(p+z#2Qdl{KWx!*8SO4hb%v*6P zhn5clsTg_ST>av?D@Dr%r8e+%2&SYIUL1?DS-+mQ%<#icG!n<(ug-npJD1rYt*-}YqocT$4L$Io!im0?sXPxcqnYyx z<0lcTG-SvJsSEqxV10iv_@cHjkv&FSy3l?mFxnGw@>tj4UZ?p6@|CN^Ed#)O0`rKS ziR(^t3v`!N4l_9VG&E{t7g@EMebe)1Y+!EJx07B~v4Q!)wy%Sf-?b-A^76A}p{?U( z@=YfJTi$C|wfdx35FL@V#K@7e)xjWc_BW6lcyn_#Ay+C|TAXFx{4JR~>FvbO6phu>l*_CVvM>m3I z74R>AIGgaX{ax;?y&mXv$8<-)uY*s?dYONs!C!`tWrH#Jv+5;SHCW1&qO|Mc`>8|E zjedzxNX&>C+&5$GzRTzP*A(t1&L)c3KuXIW;qomOT|6EMX#9GG@Cwh5N;j4dbaM+$ zscgDRx}b=0sR=xQGA@UfbS8GQtilgrbDBUz5{rV^Kj3jF+EsG8y9|Mc-a67@0kJp7 z`W*Uy;vV<*3Tvr*hHh1u+ucP+qnbxp$gEaDTmAq~9g>2>7FP=>ov7^gR{0jgDI6bf zj`--LHyNo}a{gCjbgRV%3u%m!n8){c1|`zNqP7@wRbKl{geCz6t$mUU19?BK65DgM zRF}%>mLWp-LVl9eIsIo$O|!p)&KX6S%kbp=456d0r)hQSnWt$Wp*zRohPbgiH^Rdn z_4&bh0ejkH;MOyE7|kC%RRFGqoqMM#%wT^yhBz>8Ag7+Q^J_o|t zk|pO=g~I*#jvvh4on$xUS!(gtYA*O&|P**T3DzPPegOX$7vnpiAFb3go52@ zp6HJ|rlbySV_vAv&IleKbu{V&uT(S7H4F|&uPvcYp-V!7*P_7sRu8@P{2Me1n9v`& z)vCZt2$2*JhA349v>LBMIaUB1ATcdq1?vD5Xi*|Mr4p$s&Py+t*EB4Y;J{F0h$`1d zBb6-B8=6wJEKi#Jdh|E@#yfG9IgvxS5m|_0M3BcA}Zn_hHs^S7rE@)kjnA z1ZbPTU8jUX6Vl07Qq1&Ap$TUgcgK^p)wfQYwR|cnzaUiS;n&MmsPwg<^ZXu~YsWYB z#@lm#W0@n|S1xlW20v_R)W{5DIg2{M%KvfRZqUx^eZ#oxcL|IDQgWi>0Rg E1z#s(%m4rY literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_merge_left.png b/starpilot/assets/navigation/direction_merge_left.png new file mode 100644 index 0000000000000000000000000000000000000000..a713f52c56dddf61a60a7b2e09d9999eef265415 GIT binary patch literal 1535 zcmb7^eKgYx7{_<7L>M-P6ys+IStz|Q)NE{M&D%}4ArubfEk<4{FKHUhlGoxUT$JSP zmaAXtdy(Gx!kd4rkZ)XI_GxJxqsg8d7kHU&hyXnJm);;n?oeHf|YcYKp+qp zkHdIv^X2zcl-sUl*#QmP2qk*>V7JNPaOUUdMIwsH+1-m25)q%AK`kh&e%$nYaQN-i>|a9hmqde!JP=6U z6puOKlXPELzEJegPTd8<62G^5ax$fo{(Q?_e=*87T?t`WZGJgo>t0RdNnt+`K5K&? zuu>WPCr0|*$&5yZT0v{lU}L|sf*}*W2%wr89Wd5|$Pg=u00}rYFX#-dm|x|FoVLj) zq5Oi2Z73hdobT=?Tg&+==16vQ?+ptLY@tw|9pID`FXZ{tjYMEI&sWXvals!~)OmI+ zQtsF; z-`@Eb>}f(>+(6@LS8}TcuwzVM3{1Cs&)6~asHymtVIb_U2cC(&4nWOWmG_CEW zGySi~-6PZ;-|zU@-+{tn*K{k?OT$0z@_or=>1ute!)=T~54l zJayay&TSd^ns4$}AzdGyxM5qCz89{LfQF4rOA0qJR{W4iAWfYjj*T((IYFf{Ffyxr zUR5!nu4Qm(X?&NjmLlL^zC`9Yt`^lc-VDzAe$vw^{GEmwdr9wR_!}`PRms7k{dMv3 zo_mad)i08Fq%GC`F{$H(>ba*k5la~;$C2rT_FE6co(Jgxdb9HiY0iS_F}-yfz6o$QdaF@B~It4%0qL)hgr(FS-tLk+6EBx0%0T_Gl0rX*$FjkrpEmQ zg>bQ*px&An$RYU{7b@4g0WuRms?}|-!07B$Ow=0$U_G$m9!6`8bfL5%9Sf{q>IYzX zU#N$}O?Z4|MkmNO>J9iCiLr31D#dMtrL>rX-Fx3}#nL7-n#8qmv#iG+ zN^Hb^ZFTCPhI6Kw3Cg`xM44rpXU%Ff-zn!j+l@62e}*mz#-i(j43^HR$)-(7>?q;!=J|p)+VQPoUC@xF|D@oIzfQjTI9Rw z%~UqhTy$)jIQzNfOOpS3-<~7d^`%HMJfLN`cB|9Mf*u`8ef2s2H|p{)yW=c|rwU}W zIiVs=_!YneK_Z$IZT+%z_oKl-ekAsyUT8cZyQaR931oclW-s>S>pwlHl literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_merge_right.png b/starpilot/assets/navigation/direction_merge_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3390b31a05b26bbf1e96eeb09662abcfdc076d1c GIT binary patch literal 1484 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 U=v}`@w(@=e{Lq0Yj#q5fpVI literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_merge_slight_right.png b/starpilot/assets/navigation/direction_merge_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5289011d67b43bca6345d3b86f17a57d9e618c GIT binary patch literal 1699 zcmbVNdoyNNed$7Q9iVO5EmilB8F zRkYd!W!1P_LYL6iZBk4t8_FVU)5(;s)YA8ycjxTiea`bdpU?C8e$M&)_dFaz;Ae)A z0}v1hWQfOMf;24su)*4zv+8oFKtpi^e-c*1GMQ{;Wksb@snzPOt*t-)hj;(S_TRDd zkFdMDD}!C0)|3G$L4ib&F2oq-@Gqp#DPl+zGdbg{E2Y(q{EoiiM?XAUQoQ_aV+(z} zQUL<(k>D|CQd-T+Zxk06j~V#Jfy*X3j>b4+RJ$cZ3pUbHw|+iUkYYF}nuq)}%WYkRT^DoW&-4^sQw-(jr&zR2d4^)c zkI+Y$Hr3U7%P2)iXyjg_H+NEwA3etUi0`gQ`meech7AYkpVOx-$`q%lBwkyg-l1~~ zFbUa+6#&plh8?j+tnL)@&nbJagAE#$5ZmAe%aXxU)Q_bGo1odbo}<}4-k^a-rha{O zFE-qXZc+E<>5^6nen#?zVuO|7xcQJP*A9n$tWg&tYujhRUW}ESfsspE+h>T{^%c^$4{xVA&HlRuk=Y5=lJbdfRJkWbbb*lVEslQF|LkO)^T8sruJmdcYR}Yt zc7y8R6>`Z$bZ+Kh4DfKb+;794;S_zaL!F zFUw|h4(aQ#y*IMpJE2{IPg2uzt+;-2_l}^8f`x1E9kXvp@2KoI=g<8+tVQ{(sX-II zQqu|_dX&FBOK2=Ds$fzJV9nM^i%U%GdzhO)3Yw3B#{adp&7s5aLUta9QRNk(recuS z*_TBu!bHmKO)zpU;-9&&S8bt^yPG|ZGbL>1bYj-q>0;cB+wVCR zZ;rv&U;Vh6KF?)hZIX9B*(?0@M>bCGS&>=C>a<>5Sn26b@VRGIn)blr#DBW>8z=gU zVP5?)=;&YOSOgD4bT3XK)Nbf9q6%>tYtQG1hvX#Zb%lH}1bKkk&fYw;M|M256G(`P z9Hhl8cnO1B$fZ>HTSF{isPuA@S-K|Oq0ojo=7hTR&gXflE zMvdp_K#|=ERKsoB++B=rO;q)*ReNLE2d~AXP3ia$7`gPVIwR|hYRznfW)Js&Zu9_& z33@65zpIPs4T4g5t30vG`Er2%G}kq(DUOy8^x4U&W1bWCrR~MTHRN&K2|F=!{fW93 z69b$ayMvTiC*9;AprO2@liXA+5dXBEm?61LM*&$B-sf~Z76Xb8F4(aS$o`B2{&obl zn+M^#C`)8bsjz%qZc(zm9IA(QG>)(c{^i`d7X-84p4Fo0S3@vT>_~3%`HqjE2>alB z5BwaAf6M8-@OX)8%5JQ^Ey@%-`{shvM<>mEdGblCsU)ZLU`<6nID6EsZA8^`Ei3?;!!mhmAl4RWntxY6h93{XK-_s3TLLt~Qkynkwfg!lG;U*@ z|2FgNW`PnKXWNga^V@O2n+k=fj4#VLEKZD~RGK4aMI5lh{0St_CsaKDKc%H6)F6*2UngGLH B9D4u& literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_new_name_left.png b/starpilot/assets/navigation/direction_new_name_left.png new file mode 100644 index 0000000000000000000000000000000000000000..9a618026f0e00dd044f359e1f3fed8c668c63b6b GIT binary patch literal 1400 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 ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_new_name_sharp_left.png b/starpilot/assets/navigation/direction_new_name_sharp_left.png new file mode 100644 index 0000000000000000000000000000000000000000..77106b493ff6d51acd0e3f4612baa028c6937b5c GIT binary patch literal 1549 zcmbW1S5y-Q6o!LD!;ldmMG%1m0!Y{e1qD$^WbYAH5KAZ<8DS_|Fh&fblqq2&$`Cam z$S~{;GKGT3UX_H6jF3d2^r1cNTTj39-}~MBbl+~QrMUqQmnati0N^n)L|Pxa>(Am~ zKkgYZu5XUzW@&1RI`-)3=+e^C#>U3Z&JLYU-{0S7Fc?fGll2$h|INXF=IH3C7kLYM zd_w|fZEgcN#m#>PDucM7XJX^x?t{CFk4w&cQS!d7rDu3zcIB+cBp(29QpX5+%{C%y zE&B_;MCJ5VgOnf;9rOLDQ7rVjh$JRSrixE%;Qd7dRYh+SYqvn|asEH@&E$%b{mNQE zQ`XHLQ8wt5Oy+v5j*^$SyR*4E;2@1$O{x95EdiW|F0 z*&ME^Fk|gyxE`pB%e-^1OxUQ`SXXd=E@KlW%L7TIPF_(r zLfzXO+jlS4)e0jf1Cqyrs?(Fz*IDGT`_&EtIsw(ctPUO}uXTwVO*ymcQSR7u#5ep* zZ9LCr=$Wf$idIf?6nsTnZiiPjNg%?DKerZU#TQlNM+Z-6R5c5RQ!e$FGrwuufzcF- z(ssu#9=3ooQXbG8va@>+BF16|I`c$=cG_~tyth3Gq^=p|P^75KSR=3310|Vn^hEM` z_chw`(7~mKMPy8A6hv3OLN_xPG%I&Lk?s_8SbuqFgmaHy@V4$x;X`rk29$A+m>_G| z(r0Ysq^1GINd&|di{0p!x9uCqA^YtDp@~5{XAAoqt9)#$UJ;NV?_AiP8Z5kJfkyjw zn;9JWrz?9zIqv=OFyZ>j-tx<0MnX2=nfoQeuy-3t5KuUr^a_k4feFS?xP8u zAGF+>0QUBKrfr<26B#?6K}MqDpE9y8&o&&`Zq8Tqfx$G5rI2ju!vcg+q7_1*b7T)! z8T#^g*}LBA^nk|i|EQd7E`gcg?@C>AG=XQBrvGUJw5frSW>L{*jS>{%RK zYJMy~{0l3!SXT*ur+wl2>IVjaBUr0#FZ`}4Fr)9Z1w{ZHB*d5L;xO}J4zlGH_;&7| zL@K)NP;7$0DB!S96jw1v!g2!d9F^P7k?3Rxq zZ(xH^Ied>oaY~Eaye2U?MDc{Uun1~(s?*h$JNS9LmGt7dekTtj7bymkBUO^5@rv9c ziyvo>KUbjNg~i)ziq#So#n?)H_1)4UuO#Ntv!H=8ey|RGOSPKt+%HJWR7qV+U#?7! z5`jgKPqwFEvn~F6pn9N5Ea5;A5Y0tzYKQA-12r^Vl#4WiU$?;ZE&<+qBAfF`q zzhhagM7ENLL)eWnLJ(;xA`@ME#c%5NjX@gZ)p6(^N?xTfJR(~f2x6c-F WuY1_pt2_Pp=K_pS=18)h8~zWbs|9ob literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_new_name_sharp_right.png b/starpilot/assets/navigation/direction_new_name_sharp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..eb3a02f8b3adfe72430aa9f328f1bc009ef5ce4f GIT binary patch literal 1552 zcmb7^do&XY9LI;SrePr^m$j6znnaVM5?fx4iHls8JmOMJRvy=LS!N~SMmF;pxg^#+ zLe^_WuIWtGEAX@CF#0NB^_M8iPOZj~M)YR0%!ouR>qDUlK`;+y*5dRy=|6y};v&Qw> zqpcg-g!2y0067Ka-LPY3R`$-GzCqzX5pQSGiXPQ8a(G>RLu0cM6;D|JfUJcr>WoWd z?i_tOdfada8e`+mQ!MP1Uf9f1$+}S$nZmsCILC1+R7RMH_qD&Je*j2?{$0}Xl>X?5 zDQs4<#Ps= zs&d;Ccv@5AzFPSGJT0~C3p1>N&*5H@^IyP|>1o#2V`Gc8o@{r+UGEc$i{UXRAAJD5 z;RWND)Em6slqC=OgCboHW_C}^cb<->wL2@Zo0S*qhkDAAhqpCWX=%EXdUvWf&`mKZ zqHXCPNKQNQ^(r&yn+NI9>zJUGt0E1G*pEQ&0*a(X!oG8#UpVmE3f4@-zFUU;G zS5nMSk43u({Y?_(s$-uQ8k2ONqg_IfdWnLyr+J-e8!-JkW{RY#d?hN7-1sP&-1d90 z`hsB1%Wt7{SDPcMES1kivfJ|I^HO$3h*5b_KeiaKgZM;1ri>%Rg!M+yGtr&-Qb_^t zyr||xisg($aJ91p+hu`z7^$}*BC99MQoc$aIu2q6cL>^o(;9RjVXn{DNpAa*pX*RI zTs7SDBdaazb_=fFu-^nTM+>i-%ft=?DW#kjeF%E$XxPL`hu^m!6X|2ML0XQu%vUh| z>TIs(7(eXk(D93Ic8ENl+wig?8Tv$5Tx&YkK%Caz#=d+g#P#(VjP5c z8%)2R#^_11B(EfASB_cd0^}h=MP|h(s1MEb4q0R1cGH~TebhQ!G?7wzW?iwjcn^*= ze@{gT5)jE}YD$*XJuruIZ35Q18M|<6=+jr@?JXc~k#q65YfY!Lw!C7p0sGWN|9RF% zM-3H=-ST2j=l5eB82ls-#k8rM%JgfoGc7CAaOXBOeDo=EX3$$rVU>a^ivd$L94htR zTT;Z`c9e_MeD^*~f-kwA!vj7%sES5`30*%Re=Z5sgx~|T9_ne>Zv!FhoQteE_;%m5TFFlI2;{wn5WpM3f4FBEabn}@OCyXuz8_aAcaKVOi^_YbCPjY0qIB& zalzi0cTm_UW)RS$3Wge4hK|cUDLLfD?JR13O=S=uF~@zRgD4qj!H9>UG(X9dVxi)_ z_E7d|KimT2^b9!2HIc?7$Z$hhCu6;c15lH~gzySD;_Sq)gk_d{1+r06C`QSqmwes} zB1F7?XN7MVzM@T>;_)w&jnN}eAI47jJn^gc>xpTxL>Wb8Y)7B-vzolyirr>~s^142 zREC6*fk;%+UKj@q8M{Ts|JPcKggujlns3bB)TLfDP!Q6_7IbIX2YTbbw9Rbj=<(v? qd(wPftbDvFo+$li{1Krwt1`RGTfKAJ>bP663$R5ypeilBiGKhAgAFJE literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_new_name_slight_left.png b/starpilot/assets/navigation/direction_new_name_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..08e964dbd6a68a9b82983499adda5a8bc78ac1a9 GIT binary patch literal 1334 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!Hk}t5;vVc=7)I`!8R< z{P^+X7a078fj_9=FVW!t|NrUy|2Tmb$dv^71v9X53y7;4TRV9LM<-0O!S98_ka)FR--p$H*(I&$YN^{laaWA^&#_v<-EeHR2-Khu)uSPdrqs z%R4_kOFgzOFZ@OC|B9V|JNmA*_TRq#A|ZB;P0O1L2X}oatX{Wli_nLn->#`#KM(3} ze;)s$;%&vVZ>m;t+ID&Rfv+pxd;MEuvio=VrUVZT~-`@|9kHuauHf8C3urD;jug$lQ7WE{R8R_ENsB1nK6-!NoyQusn?w$u(EV}!t(|sFPUhBzqmM7|6koqS zQY}vI^yd6|dEf8Y=$ake`Q&BU`Ow73m;*7N3U;qvE;R9TQrm17n`2@BEFI?EdH7Dm z<$IC#gPE^FM1=l3cF4|@*`)Krw&P8?sBwtB+O0QoXB>r?sv7?Yeez$Fxaw_pMA6H= z|1#WlLN=VOmY6u@-rnHVY)70GzWgz1nW>V}A-&`ScVXKhh14R>Bse^mVGt-SN)PFm6r%Y&UJxM@1)+;&yW56O@W<(c9|iO;O!eu1cJ!0T-+CuOctIiHwC5+gYjanl%dH3>VEM%0>FVdQ I&MBb@06s*zH~;_u literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_new_name_slight_right.png b/starpilot/assets/navigation/direction_new_name_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3e21cae11ed5209a7f63f7352d7ca2c4ef5b0b14 GIT binary patch literal 1347 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HkZOP5}}c=7)I`_G?0 z|M>Ca7a078fj_9=FVW!t|Nrx>eU1VxkShuD3ua*D77$l8ws!Ikj!w=lu5Rj@JbTIN z&ASetxpL?6>mzF(>N7B~lzX~3hE&XXJLl%K#Rfbsk(=NDcKi3=cy@`EtojKy>pAO^ z+`gA4^sQQ$<0;muSv3bA5XEv~P#B&%EZJ^m3=FqQ-iAN!e&YBlp)Dl5e5}nm+IH-1jen!;$a5 z@3uc@z9+1oy=3!gcBc<<<{if$Y8p0Q_ig*_pePe({xY|@WkbbX6_rxOPrE$LzQ-O~ zu_tem&z~h5D(^0MuG(_`wf`QoYPa?FGb&#weElUme`|I(-!;c)kIRzQKaUGN#UQ(G zYUBM^-mkxQPVadwDZ9RR>3qJh_3HPg>My@;{C`o)rPq5KCYigk>k3?2n*QaNjRX6_ z>ytMeGn;#Tv-1Q#tM$(p<|Y`e=XbU)Nr{`!c1q!MRZMVgPMUVMd{GaZxg>C8n@Zg7Hii(G;ZOfLawn{A6u=DZWcQ$4g&p-K2ZSVNL zYqOR8jj9DxugTtdeQr<6`9n4*S3Nd{S*$ zee>ZL_D9=$w}*fF;?5X7A*ffr&(vM^#hB+mTg^sD!a7x>n_{k_-pt7?8iRnZHtx9QDx4?ezPT|?aVIXC2NoT}swG4IXu6yu(Mv32=rps3A+!oPFb_UkTL z_S*S(gv_IxU;n)IeY8h!yZhd_H76?U6XVuTaV_6tFQ#`PZu)Y@Z}n~RPnfUo0pPfKqz{iF@ zEryLD-@W}TCX^j!x|6`|=u=Zz9cA(8(d+$^k0w473)s)_NpOi$F3PaPp!@`z0o4S^2||x zT^5DjkFpmXTNR$}i`7|mL^$(S{`Oc8^#yb9@GouJ+srFsdG*y2ftQ^npRP`_aWdw4 zci4V&mS^cyF2_YqHv$xMRtT7da7b&l@QNO4<4SZEdSrj!r2)uj-LMdwywt-NDQER+ zjqjdhw8~tzvD(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_notificaiton_right.png b/starpilot/assets/navigation/direction_notificaiton_right.png new file mode 100644 index 0000000000000000000000000000000000000000..0fbaa3f253edb8511e0125a5b4bcf8c6e7b4177d GIT binary patch literal 1371 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvG6Q@n>Sy)c=7)I`%j-f z{rK_Y7a078fj_9=FInLK|Nm28tKA1$rc@H-7tFxUEg-69V(sJ|6qTG)T;1F~Y4)Nu zn|2>QefiFVr!U`r{AQ}bX~Mw3Qt#>F7*a9k?Oe{JM+Q8ujVdCiZf%&hw)1`ciJ32X z8dZvNEKh8*u44E2dT`=C-I;uBO$r<^^k;v{?nj%>?pXZ7zbttF&shb>FV61$b-K%X z!oE5GI0JvTSWl^&^WN!7>KR#YeLF41Rdb5jFSl>0(FmL^SZ-l^!-g|(zToqRZz4Oi zmfiWdWAl2=!0dMwb7o#?UEzF6cB1xtUe$}w9!5HQY^kiM$kYnFZSncTB2|~Ui_RQg zylAb;Ih#Fs+?~e!*K544R8}x^23|LRx8p*}0)bGy9n8*~+ov9x-agxIsnRZ+J6|+K zk6M>!SVY-9J$QVAwS`FT{Gh@fEq-RZrH{md<>YEhH3GfgeGq7{Tbd+(exvxCV6Af> zpCsN`9x}!F9YgNLA5+*Xbt)sC2WusrJe;ql_)5(4x8v(zxg!_rD$Kb%m;5c*8c@{t z@W$%|MU^g_8ne?soIh0VIDGm#=kC7-Q6;mdq*vTNaI<9JJ-Kt+7q#q&T>Ya>lVAPv z)qR(jKTbSx_~xlammYq+QzxYTW%Wa4{^dJs%}U$% z01adE|eB#b_zFE!>k9>dacty`Qqc>D~5!a(w_CVk7YnxA{s@ATyyp$C5^WMU%6R)Ih zpXa}+#Dqm+iFb?Grnw!K@9%vozq~s$w&lgQwq*icceDbd@{YXl^S!@I{Ag<8PJuPo z)D!Iu-`Y&JI=jZ-Vr`jWi|oC1O>qi)US4rxOFh5$^$D@i8eJoc)bF}i-!Cp;4o}|9 zcWI}{-$PDfYv+2hy`9)um#AoOms~xotc+X2{vZ3b%QLgIK5l#z^t)C;K1Jf;0=pN! zCDA2o`VOuNX0PN9F~8hww@|WFEc8=aN1koY1^-ti*j_CE?~Ys# z4crj_`{f6P8*?jO-#RpZ@nJ>#nBG5MFCKjOa<%g$#?=##pJX#gw>;C);Cw?a-B+j} z);dK0!R)VAt(2O@`$GxN9_G$b)c6VXjeCKa} z-+69`JJIULCOhqTMf|ktYcp#zgauEguCr27F>&$8=$LRpKyjg>laq5xOB)9#ub_|= zVTm7xPH`p%2l!16DLPsFH1zgH)B8t4aYAO#qvJ1UGi(=Ff5*_0@lI<0V|n>4H_S?9 zl7E{gl)tjy5c6c?D+!*q$Lf!!D#FVTj)@<+XC~|a;`*a`2Uu`1c)I$ztaD0e0ss*f ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_notificaiton_sharp_right.png b/starpilot/assets/navigation/direction_notificaiton_sharp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e3c4cee56a7de3cce450a83f07fcb55202ba71 GIT binary patch literal 1551 zcmb7EeK^wz93Od^X=80txm3S0QVx~$(7WH{ZOdDmDT|#$Td};HNp5Zyn{vBRxk%bv zXob$pp-^U(RLon#B=bnxIl~&7xZOR^Jx}-7J@A2X%|UkK{<4R+ZMh_+)tpUa0txn;o-}cX+Qzp(vWt$)}GU%UIuWv<>Jf zx?e_bXfWub^9K`TbN3$j=lV*Nj@Tz?A^wPwR zuvKIPKa(=aILTn=9{+_BR>%u+S590Uv-Kx4xTW$ar+R#I6;rk$1Q7*0x(JE_28J)| z$Ind9Hv7$piJ;j@0xHU3u+PFPfFZXN#y;>gV)xa4WQWaPER{835GED!ae?C>A|1fC zsv?BdqDbU776q3&AaCs^nhV6u&hKkM z5AB_tdww+KR^m1XWF#ZWC(5GZV4*V$5Z$v^dq-|&$o4E%IU}zO_C0D>20QVrD?CGy zSNgpvqS!@N}5 z#%Ek-aQ3v^`F`wu?L#T`@HFVsU9!4H*=7Ifl;${)Stq6~&t_Ywr?r|R_Qc4?1=~2@ zM`m#^Td36(nuQnXv8&23Xrg2-x%a%)PJ-AI*V_uTzqB*=E?6}Q79-DI$kp$9a(f=2 zvQK~A5EqUS!ssQ4Q@Ym=YyEV$aT06+s5kT9+!yS^c5_l)XKiqufq*Z=FHiUkyr~3y zQoFeuN3f+vR%k!c?WEXk>^xsDSD}0>PV>itFS63oa}J89EE&ANm*z55n1G zL*r4-sZQ7;PO9_S6+r>JSgp`TuEnD~VLZ}}x7v`F*@ad1bBs#2daZ6|(wd=xD7lR; zE_EVz_3MZ#h!b`KpriVryL5guefU_dO5jq{de}gFO=ZKHEbH$6r<9sEzpFE5P-bAB zFvdnYq<_SudF)(O3iO6OF@IB+)&maL>t3C4J5!HWGCSvHdMZOwrRc(D9%DCNtYng1f z$Vhj?PqO{GpSyY<9WJ+-cI5V|zNAOiO4gT>eUG0kcPX2)d0o;oYZdKjrIJTgKgmvJ zy}D*~#b?@H%CcawFGG@5CSOn4ED}Nm-$M(xS+4 z!7l5{%-w6(<gzHO_-&?!rMr~fF#8Gbac8Xw&^~)2xx)|pe8ySA^f8hHwySU!HJ^F6VZ{GJymbPt)dNOC~nO%?dy)Ea>PI-R*aNX`X{%sr0 zCHFhus>&%9^9mM*o_d(r*(&eJ59;+PBS?~~n)78E+}mr2)KbMy*iiOecNw()p`AQrc27| zTF;yM?K>2T&%JQy>S3KIRN~@stZmf=W#?$CZz27APVZVVWx`DTaKERsWoHVh-@Dj3 z$z^wYQL3#^P{Z?!r{Cl*o_>Mzy4si1HOK!LNS!sc6FsE3ByZ;aj2P{C+k9F?TWpuE ztGvy7c3S4Htp5o`hwQq;^yBKK>oz!iSNm7IC}&f~)XKl%OID>pF4Pq=ihnHa^W|M{7o z%+8%MZ*MG4y?1E0lKJ$-d!4qNi9TcbaQ5k&uXKZ+`PQDA$`O-QT+Se^_t{L8A#Ou~ z`QbKmE}gC-o;npi^P2~Z^4|onYgivCw(^eLiZjtYS-~If742$e&Y3T#tH(UcJ^Z#{ z*AB^M*T8uWPA_x|rn=4C9+A%?U;bSC)#Iv}+h2$|eV_K*^dyk^L*ro3qlXq=XH#eV zUXt$7aeH}eU~KT_51JR8opu*D2WWm4vt!L-+u;}8>?R=&`+Hs%ZYkRxeW7pr5Zqi`jRB%Z@ z;N_8X)vTfANp1TxCc#6zWTD=6u}77O2l!Am14Ta>EDLP;k@7*~JV!}`%7*%`Qf7n>Sy)c=7)I`%j-f z{rK_Y7a078fj_9=FInLK|Nm28tKA1$rc@H-7tFxUEg-69V(sJ|6qTG)T;1F~Y4)Nu zn|2>QefiFVr!U`r{AQ}bX~Mw3Qt#>F7*a9k?Oe{JM+Q8ujVdCiZf%&hw)1`ciJ32X z8dZvNEKh8*u44E2dT`=C-I;uBO$r<^^k;v{?nj%>?pXZ7zbttF&shb>FV61$b-K%X z!oE5GI0JvTSWl^&^WN!7>KR#YeLF41Rdb5jFSl>0(FmL^SZ-l^!-g|(zToqRZz4Oi zmfiWdWAl2=!0dMwb7o#?UEzF6cB1xtUe$}w9!5HQY^kiM$kYnFZSncTB2|~Ui_RQg zylAb;Ih#Fs+?~e!*K544R8}x^23|LRx8p*}0)bGy9n8*~+ov9x-agxIsnRZ+J6|+K zk6M>!SVY-9J$QVAwS`FT{Gh@fEq-RZrH{md<>YEhH3GfgeGq7{Tbd+(exvxCV6Af> zpCsN`9x}!F9YgNLA5+*Xbt)sC2WusrJe;ql_)5(4x8v(zxg!_rD$Kb%m;5c*8c@{t z@W$%|MU^g_8ne?soIh0VIDGm#=kC7-Q6;mdq*vTNaI<9JJ-Kt+7q#q&T>Ya>lVAPv z)qR(jKTbSx_~xlammYq+QzxYTW%Wa4{^dJs%}U$% z01adE|eB#b_zFE!>k9>dacty`Qqc>D~5!a(w_CVk7YnxA{s@ATyyp$C5^WMU%6R)Ih zpXa}+#Dqm+iFb?Grnw!K@9%vozq~s$w&lgQwq*icceDbd@{YXl^S!@I{Ag<8PJuPo z)D!Iu-`Y&JI=jZ-Vr`jWi|oC1O>qi)US4rxOFh5$^$D@i8eJoc)bF}i-!Cp;4o}|9 zcWI}{-$PDfYv+2hy`9)um#AoOms~xotc+X2{vZ3b%QLgIK5l#z^t)C;K1Jf;0=pN! zCDA2o`VOuNX0PN9F~8hww@|WFEc8=aN1koY1^-ti*j_CE?~Ys# z4crj_`{f6P8*?jO-#RpZ@nJ>#nBG5MFCKjOa<%g$#?=##pJX#gw>;C);Cw?a-B+j} z);dK0!R)VAt(2O@`$GxN9_G$b)c6VXjeCKa} z-+69`JJIULCOhqTMf|ktYcp#zgauEguCr27F>&$8=$LRpKyjg>laq5xOB)9#ub_|= zVTm7xPH`p%2l!16DLPsFH1zgH)B8t4aYAO#qvJ1UGi(=Ff5*_0@lI<0V|n>4H_S?9 zl7E{gl)tjy5c6c?D+!*q$Lf!!D#FVTj)@<+XC~|a;`*a`2Uu`1c)I$ztaD0e0ss*f ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_notification_sharp_left.png b/starpilot/assets/navigation/direction_notification_sharp_left.png new file mode 100644 index 0000000000000000000000000000000000000000..dd8a4301db6dbee6bb7df86a7a1d04dc813886af GIT binary patch literal 1546 zcmbW1Yd8}M7{`}eBf?m@h8<2q%COusnOkn*n6QzJ%6-gzv80p9wGtss(S+7^D2z&_ zwv)s$h11_5OH{Tcy@M{&*!hKtOx`Gp-}k!`}g(r^^L#u`@gmMpS8Wc z{l+m)M|49A@8jtUklLl7qVuB>%;C5%3KNMZWM95kd8eVJ<9QEz{KJAfxl^<%Y31q& z_e-r>yvYo^a9Gw}9aJGVYW;OPYZTTiHluSg?_9t2g~l?_C@W!OwN5|p_CLJjWoPWa zuo(OFeau#X=TnSx4&~^{n~_A0MKV@JN>Be=UmfpdVP8>n^5LKf3posP4({*2yWr>^ z`V0IN^hfH)Y-zPa3aI5ZJrj2R=XX2%D)@G#@gcCfHrP(ira-Z2Mp&k&7 zv4`q57KB%nRP8biwuawq#b)j!rnr)9W}zzrP6^eMCdw^?JFcQNECz;*O(*v2C1lDz zVsd6(kcQI*4v^7An#@nj%@o5RTeu7McQrZR*^nS}gK=*M$fqc?Wp@AFI4>kJYEl7| zwu{Tl@XC}5OT(GfHZnO-2tVXx2Ea?>p&^C=0-w#FZ=I|NG@sX-cm9QBc6-U-P^rB} zz5Fq!T6(~eK59*DptPPvH>pmPoM`3Cpb6J4A&|$PQ>nIPG`!vcXe8oe+gLUAQK4uU zK%WVSqSbKSe6Ztc@saH?3zTbKaG-c>K5~s`9cjmP^RDIFYCAJP$~W*%W;_~W034BZ z%mMqGsv?!&F#w+TaB`^aP&;a0W;p;(V1_tI2+8N$$r~9_#Dj~{xdicJ$*^bXi^`l@ zhrMeOjuBnOi|@L(6x-$`gD-5f09&ra3~`@~n|fRoKV|K2FJVM8w+nM-jCohw7b2jc z-4QxF)7K`+i!YZh=MxpxACL<1;X&o+{3Otlb_;mb6b4AiBzlu0t}((MQoTj(c9ccT zZJ$1_jdCT)y2GiNrv>-y8CO8`CbDN?W4kv@=am`XYW z1X2~7PNT`kCQt9FF<)tV5j5J4=s))=D<03lT^{L?)&?J6&}nv|fM%u?%c)q$S6%VR z+3eE%TnuS4oR7S{)drl;b@t%3f6oCXSaq+Z5ZooydS$&BAVr+Ad}VMz-^ABE^7SX3 zvnSFJJU-o{TpmHoTOmHn7YgcApBacDvt_l_+k$5U?4s~{W?Z>?mTWe5ehnmSfJU6A9O6DZxVfJv2_R+hF@NRlz^ zqvzRIl7Ys}WFMJ3xtJeb_dW!sqOi*J*5$Ml2U!=boJxvKs}7aw;RL9h?rkw_YW!42OM>kw~?i1Mw(z2PQTrAH*nSmf;*qKEFr5iMH1OXUBy zJ%`cebk7gKI90!`pktgy!SGbt8*^T#G*URrMdZ7zGiaL|CYnN|GUCMFzJ?d>Fr)w4 UAJ#<^{aXOQ72)YfbqLM=0~U1z7ytkO literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_notification_slight_left.png b/starpilot/assets/navigation/direction_notification_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..08e964dbd6a68a9b82983499adda5a8bc78ac1a9 GIT binary patch literal 1334 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!Hk}t5;vVc=7)I`!8R< z{P^+X7a078fj_9=FVW!t|NrUy|2Tmb$dv^71v9X53y7;4TRV9LM<-0O!S98_ka)FR--p$H*(I&$YN^{laaWA^&#_v<-EeHR2-Khu)uSPdrqs z%R4_kOFgzOFZ@OC|B9V|JNmA*_TRq#A|ZB;P0O1L2X}oatX{Wli_nLn->#`#KM(3} ze;)s$;%&vVZ>m;t+ID&Rfv+pxd;MEuvio=VrUVZT~-`@|9kHuauHf8C3urD;jug$lQ7WE{R8R_ENsB1nK6-!NoyQusn?w$u(EV}!t(|sFPUhBzqmM7|6koqS zQY}vI^yd6|dEf8Y=$ake`Q&BU`Ow73m;*7N3U;qvE;R9TQrm17n`2@BEFI?EdH7Dm z<$IC#gPE^FM1=l3cF4|@*`)Krw&P8?sBwtB+O0QoXB>r?sv7?Yeez$Fxaw_pMA6H= z|1#WlLN=VOmY6u@-rnHVY)70GzWgz1nW>V}A-&`ScVXKhh14R>Bse^mVGt-SN)PFm6r%Y&UJxM@1)+;&yW56O@W<(c9|iO;O!eu1cJ!0T-+CuOctIiHwC5+gYjanl%dH3>VEM%0>FVdQ I&MBb@06s*zH~;_u literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_notification_slight_right.png b/starpilot/assets/navigation/direction_notification_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3e21cae11ed5209a7f63f7352d7ca2c4ef5b0b14 GIT binary patch literal 1347 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HkZOP5}}c=7)I`_G?0 z|M>Ca7a078fj_9=FVW!t|Nrx>eU1VxkShuD3ua*D77$l8ws!Ikj!w=lu5Rj@JbTIN z&ASetxpL?6>mzF(>N7B~lzX~3hE&XXJLl%K#Rfbsk(=NDcKi3=cy@`EtojKy>pAO^ z+`gA4^sQQ$<0;muSv3bA5XEv~P#B&%EZJ^m3=FqQ-iAN!e&YBlp)Dl5e5}nm+IH-1jen!;$a5 z@3uc@z9+1oy=3!gcBc<<<{if$Y8p0Q_ig*_pePe({xY|@WkbbX6_rxOPrE$LzQ-O~ zu_tem&z~h5D(^0MuG(_`wf`QoYPa?FGb&#weElUme`|I(-!;c)kIRzQKaUGN#UQ(G zYUBM^-mkxQPVadwDZ9RR>3qJh_3HPg>My@;{C`o)rPq5KCYigk>k3?2n*QaNjRX6_ z>ytMeGn;#Tv-1Q#tM$(p<|Y`e=XbU)Nr{`!c1q!MRZMVgPMUVMd{GaZxg>C8n@Zg7Hii(G;ZOfLawn{A6u=DZWcQ$4g&p-K2ZSVNL zYqOR8jj9DxugTtdeQr<6`9n4*S3Nd{S*$ zee>ZL_D9=$w}*fF;?5X7A*ffr&(vM^#hB+mTg^sD!a7x>n_{k_-pt7?8iRnZHtx9QDx4?ezPT|?aVIXC2NoT}swG4IXu6yu(Mv32=rps3A+!oPFb_UkTL z_S*S(gv_IxU;n)IeY8h!yZhd_H76?U6XVuTaV_6tFQ#`PZu)Y@Z}n~RPnfUo0pPfKqz{iF@ zEryLD-@W}TCX^j!x|6`|=u=Zz9cA(8(d+$^k0w473)s)_NpOi$F3PaPp!@`z0o4S^2||x zT^5DjkFpmXTNR$}i`7|mL^$(S{`Oc8^#yb9@GouJ+srFsdG*y2ftQ^npRP`_aWdw4 zci4V&mS^cyF2_YqHv$xMRtT7da7b&l@QNO4<4SZEdSrj!r2)uj-LMdwywt-NDQER+ zjqjdhw8~tzvD(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_off_ramp_left.png b/starpilot/assets/navigation/direction_off_ramp_left.png new file mode 100644 index 0000000000000000000000000000000000000000..d3fd182893762edfe00c4812c46ca9e4a99beabb GIT binary patch literal 1524 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HkhTem)a`tves14$(z>f4%z%-^XK&1 z*+;^ExIe${fA$mm=h)bXdO0jt-u=s#J8Zva{q?){Ij?=^WU@}4pS9=2mUUJ9u5t5~ ze03(Ie%-Ub`+@)JT_yiiIWMpORxBk~xT7Pbz3hOa&1)Z*XVd+jxU@*iDY=?6zY%aQ z5D5Gor&WEJ$7r8N-MdN|gT+1im-=?iVojT|(RJDVTHX{X=|~l8KATsfSxX9Cs{*$_ zY|`HEF8Wg@D`C~-HbGam!0n8Ib6;F^6P9#|^DAwt6&97G+=tLEz^KY5Bf4p+3cW0XT=E=1c=k@D6nFPbHTzwP& zN32M&9O#N&n$Eh5`106!vuZbfb={&Q7x>+8Yt_P(C1M{tcIBSpdK5J8Tl~?YJpVsa zl;Q%-j}&j8C;i&XY2qFAS8T-*hr`?aQg*}&bSE?J2Ioep?;>3ue)_oQAcxC?w@gxg{Z$J4Iuds`bnRUv^ifA>abcuT zXT`L)f;Tm#1ow-toH50C(Tb-L0V)ZeQw7#~?-8j9nyQhXnS6a~#zHNr;51=hSLI21 z`|V%sU45i_qgPPjR*M~{JWLjvept=b}YQttr2@721}qov-|D(#rH%-(!qIwST9sEHV;2 zZ}NVB$KDO^T;|F1+Z^216h3SI@BZx@?k4p2>UZ_ZecyN6w5+WsU0eE{ey>S%{A$$E5HwpEHrKnsg#! z>bzN@N{7Vw+-LFUJv4}$yzF$xrj^GwI_xj&zi>1q=+J3F!HxMdTee%yyf&}ycTb1( z`8ApMLM`|VZOZqTYnEy+Sli0Cacj26*4Hd&XKpi*4_JQZ!~=#Rze{@A=NJ@APxVfH zsqT64Ku+Et-c`XSA6V}#&(t(GV{N;tS*7#i*{Mq=Kcz3*Eb8UsYjItbEZ%0)Z~2iY ztnhdWd*TC={!G)@27AwWZ!(1DJZpYE<#jFBzD6-l{%*%|^JTKqZz?U9+3aIq`tyTT z>Y@kFb)PnRDV$A?y6`|^#WA+cXB)l|%#WGMJ@X{F2DL#|6^KNBqFitrOYbGf;!iqC!tOPWwqJ*cv`V%g6E!4JLD6Z-0Gt`#5dkKVgkXy@{u-W7k&&g}HrlpFe1;Qj6d zrA~X>DqyZxI>amZu&txO*=2{K(j5W8ybca?a)mcMju-nWSM8^9CE&@@|M%_WYA2tL re^uzJ8^+J}-y|Ad&I$ah{Ks%q@2k(WzcoU@(v`u})z4*}Q$iB}KUVM? literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_off_ramp_right.png b/starpilot/assets/navigation/direction_off_ramp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..722e3f808f632c84d319bd282aa2902d0811e4ba GIT binary patch literal 1580 zcmb`HSya*q6o;8XNgEeXK}*6UMR6+^+$)zqM_e;-O3PA{GNwsN(cDoqz|0IQTvDsC z#azNRv$94_L5}9Qp?J&|9ZLfRwQwsOr_(&lg1&3ZiQEB zhEZc|{+`wd;fd!XMbh`)yu7n}1pR%ox{!eNH+BcO+t|5Ayh+J0rk1-UU(>q3P&n)f zcTrkMR&H&pq+Yc&d?<<#S8FOQ1cKFg`>Pa0g;)M(eSURw#6-BFYh0`xvNAtRZ|{Dh zIQwk3!%y1z9gQd(uHLkl_m;xxkC-c47|bYRo#bAx#a-GbiwP!flf&j2$eTLJ{rG|R z*rwy=Rlq$NQ;3a2VsuMzz#&1D9mliRA=i*41nw1Z*~@1PSW^IVnx4Bni@ovns_yL} zEPTFM;o@y>#{>o(iAaoIujHbI)=t*L9+)3TKNx_^q5^5zM3WUp;DAL{ZtVFp4w8$7 zU^)^57Y1Q;mCgZ{ebpojgmE1$a}QY_?KnKkkJ<;T3c@Zaieutfp(@oRztHh*ch$mg zU94TY`K${6*7ZitRxMHR0d$=NHpA}Q#+BBcI31$##@eh)oc6;E2)^S+iaY)bd5xA zeSO=)tH{U|U~=C%*=BV%AK?t03-d-ayyTu|yC>`lwuOdj7y@wuV%gcZ@6@drRgo06 zD~(`0f`c2dXrko+jvO2T^T?Rf(POpJ06^|;XCub;n~uehwX1Cpd6Vl4YCN5Op|Tr) zHf6mONO5!&SR+0FV_N3Zi+{oe$)q2)azm$3P1u+Q2bkpSK1J9RKUs<{5r)8Vt+lo;WHfVo zxG1T99EKOs9*<^6?>&G$G!q*0svDIm6yE#eE>cWPPup@C(yyM$VxNrNm>Nu>%x*rQ zcl)HiZR~^AZZ-EXKKDUq2rd@QPv0|Hl0UPYa~v%2ZlkSiT23jS5N6G)yx_4ZMIuyr zy4#R=gOkfB{=GbZ*P`L6uDf>B)vs_{J)cEqiq@Fa@E#A%97(PHy|_kKVLi7O_M##& zO<=dz>>*3W0~x`-9DeZedJ$DG3(%UZIT}5Y@qAoWC#;f3cF;@0 gp(>u=qqJ0l#zhhKtDsHRYo8e8iw^?scttY)0wFN_Z2$lO literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_off_ramp_slight_left.png b/starpilot/assets/navigation/direction_off_ramp_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..ddac4aad6645923290106c2a79b5c95043d5e445 GIT binary patch literal 1478 zcma)+Yg7^j6vs)$@Rf+EX+8$zV`jdxY??h36q8KUqxpVRI$dcK#TvRy94cl?X8F!1 zq!zk-zcSN`rj?;$f|#kBbQB#>;0qb;Y&-j~5Br^a|NnFEJ?DP>XM1_NsVVCz0{{Ru zcND@~=JYQOl9y=-G4z4V0=>|_NSQO4OfHwZy1FV93fI=wHvVMuZ?^u0M61kbf0D!`_JL078l`>vA z`%bkr7#Rd?>wB-IB$bxJzde`M5T5_6exyNico$>J$Q4 zsl184lv}pX*}h)0#?J8t^Io(&j(F&|y>|j^8+yUT7Ev^#H!j@ZTzw%%5`#|Ee4?`E=a5?{Oy@dz1fN~Q#CcsUw~bkXP8d0EJZt$L>xI+Do> zZ~=xTDRM?QP&m)z;0zzufd;59x>nq3)F?Lk;*+GZ0mO!d}9&23+3V1Fq6m7=d zFvz?3!`sdSMN#Ue3^&%BgY8p;*(vu#gFTCByOR1ndZwnZ)n4RyMg^^rqv%_UXBAvX zZ3bz5ED;U&UbVW9>S#5hj`uYS1Gi)B@lhm${d1+bK`WOCLjzhT2~-!Q{HE-dh>8{K_-3Xs%dl98CEW~OV`3y41O6$Yb7AJHgGPtO;TDiLw*)4 zv)3tA$P`9J%Y0mhHlMceW&~moIJBP!90}EJr4I$|^8nuAtFLUEv;`#7rsQ+hD1G5$ zz3RcW>`uu$Gwui2c8pag6RxiFF<+F9Ut%nd;xXN|PE^09S)@ZH^Rpf*DMR#x&Bh+Zrb6Qg@KAR3A3;KmKpMT1 zSy8hTIhT0iC1>SF@Sp26H`{muo3N&{OIQ#& zmc<$F06H=kd_xJ~dWxh#zC5MRTTwOP>p1hf9qcimw%VVRsismn^VGcJ3jVs*4UMZ* z&f<=p8VASCNp3e##iG(lc9Cw=+`W)>d+2FxYqGmd@F~eXfUPmoveQ%*kvXp4b2OOv8m~W71BocWw;1ygp8o+YMDI^htxk8}Rl!NTWF?+|yu*)IF6TVQV@7$({G;b0P;t=8W2j#hbmz*g2^hF41GS)%-QdWkwq(=0D-oT4rf9l@}wvtWc_j- zQu}rmwlCEDHoabQNl=NfYnA(@*K)L+)ngCHsuu^WTe=D3VR=uA};T}$^SvRY*mTK~z mx4VkRrnHcl-G7x*&b9d7%8f&icSmHA32;YxB52Ox>3;wNTliW4 literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_off_ramp_slight_right.png b/starpilot/assets/navigation/direction_off_ramp_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..ed57608864518713dc97d8af9fa88b6bd0693702 GIT binary patch literal 1519 zcmb7^c`zFY6vpGIrj80~^+3r|woz-hEmKEZBqU{BOY5k!sI8V3A?hqj(zxOnXRD0V zt(6pus3J5)sFqkqq6m$~F(fI8N;ch@&g`GN-+b@=-h6N7{rNCX4z>!i$7KNkfC2&z zbrF;Dt$dsmp4larGy7K_8-?C$Og{?Xodef^jA|Fc9Qk>Tgl;>!T_ zC>Mv{0WxxGr_P!|?OeQqBjZvZ<(1(Zh+X}|ALf?WeY|rW0KfqV0&3}sDqk;WN7oyH zY*cG$UfuJ_J4vHgT4e*3f7MPr)I2S6D0*|gYk4>bm}!%u1^n)K`PI*!uk?*QSSjj= zpM&xjAyJ4h^`YVFFJo&?D@%R@TrCLpV^DVW& zE!yCgEg75+_0==tKtwBJBd5mBr%{klq0tT72pVf3#AMX3xh%}y==LlIFL_PpZ}J0L z8LmOT7=oM2{tmz2U|TvA+G>e~cWkMgojVO_ zR}gq_y?I>LiKYaz!7OU#d!(gnQi$#7bdkxWo`ro6g(=Xw; z`gwdZVWG^Pub!|A@7p{_uu>fEOr_*4JotuE?UZ3tU!CP@jUr?ld~gQ;kua)SvTfsg zomK)K86@+%TVo3DfEJh}$zo(SypO?`B#wfd9pP32J8+d}T()CYWxO)^R#kf_lFly|=C$LNkLIYYZ5g%!l!$y=jpW__4pzJ5sUbkI4!bMz5nsVCQj^}=Hc9d*0P zu*vr9E6i9j(E%IP*nD{1*BH4bRgQFFhA`xn#{i(N*t;~1(JBK}+^AYXWTs&h~jS%o4@~y)jw=m+F%41#|dMmfCuH>DM zZxxZDjIdXsjBqX1FUpy+&nWf#Kb`xE3Sj4vNbR>$(t)iLsJj~>m}+WHKamk{Y}tcz zxvDEmrK_5=6_oae66pIds{e^6yiRl?6Mt3rPHDcGIr}^g8s~p3qd|`+p;*ByMMsB* zei~;bFA#;w2&AU*lp8F8(tmSbx2nv_AR@6Q@sCBK@W?oF`l!O(%!X_QuLix6y^e8y zANr$;7Fz@^9SG>{7}&bvk=!W4h6uGtF$(5ha0!ACG_I2to3V5u`5;ALo%Y1qU5!>7 zoghOIcn8`$eqQT;1N*aa9>)3ru>DeGu>xk-z0peoa}$0NVtoibqYPbgAy3cBmcHy0 z+(zY`;Wl&gucT!QUNf{^F}Y1UmEF6Q_uV&Dgj$8b={1XohMB{^rOnkVZouFsO1F#+ zQsgTW+zSFHGIp%=sPx>0ZeHdOy(9@TGiZdF<`{aTxjgMGp!(@&s zc}m~+n^LJp2eq4=rri81y=}WmE4(4YaOl9c_TzW3j>}Kj3f={B%t&A*HsZl;LArQD zz^iuZt5K|rzeRH=#nHnYJ~rOo=3?*!xXe?WF5EZ;Rl+FzA7|w#@r#N26J0IosA^n% y#V}y3IJ?#sWNm(UHT6rGW;*JrGf3LNtYng1f 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 ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_on_ramp_sharp_left.png b/starpilot/assets/navigation/direction_on_ramp_sharp_left.png new file mode 100644 index 0000000000000000000000000000000000000000..77106b493ff6d51acd0e3f4612baa028c6937b5c GIT binary patch literal 1549 zcmbW1S5y-Q6o!LD!;ldmMG%1m0!Y{e1qD$^WbYAH5KAZ<8DS_|Fh&fblqq2&$`Cam z$S~{;GKGT3UX_H6jF3d2^r1cNTTj39-}~MBbl+~QrMUqQmnati0N^n)L|Pxa>(Am~ zKkgYZu5XUzW@&1RI`-)3=+e^C#>U3Z&JLYU-{0S7Fc?fGll2$h|INXF=IH3C7kLYM zd_w|fZEgcN#m#>PDucM7XJX^x?t{CFk4w&cQS!d7rDu3zcIB+cBp(29QpX5+%{C%y zE&B_;MCJ5VgOnf;9rOLDQ7rVjh$JRSrixE%;Qd7dRYh+SYqvn|asEH@&E$%b{mNQE zQ`XHLQ8wt5Oy+v5j*^$SyR*4E;2@1$O{x95EdiW|F0 z*&ME^Fk|gyxE`pB%e-^1OxUQ`SXXd=E@KlW%L7TIPF_(r zLfzXO+jlS4)e0jf1Cqyrs?(Fz*IDGT`_&EtIsw(ctPUO}uXTwVO*ymcQSR7u#5ep* zZ9LCr=$Wf$idIf?6nsTnZiiPjNg%?DKerZU#TQlNM+Z-6R5c5RQ!e$FGrwuufzcF- z(ssu#9=3ooQXbG8va@>+BF16|I`c$=cG_~tyth3Gq^=p|P^75KSR=3310|Vn^hEM` z_chw`(7~mKMPy8A6hv3OLN_xPG%I&Lk?s_8SbuqFgmaHy@V4$x;X`rk29$A+m>_G| z(r0Ysq^1GINd&|di{0p!x9uCqA^YtDp@~5{XAAoqt9)#$UJ;NV?_AiP8Z5kJfkyjw zn;9JWrz?9zIqv=OFyZ>j-tx<0MnX2=nfoQeuy-3t5KuUr^a_k4feFS?xP8u zAGF+>0QUBKrfr<26B#?6K}MqDpE9y8&o&&`Zq8Tqfx$G5rI2ju!vcg+q7_1*b7T)! z8T#^g*}LBA^nk|i|EQd7E`gcg?@C>AG=XQBrvGUJw5frSW>L{*jS>{%RK zYJMy~{0l3!SXT*ur+wl2>IVjaBUr0#FZ`}4Fr)9Z1w{ZHB*d5L;xO}J4zlGH_;&7| zL@K)NP;7$0DB!S96jw1v!g2!d9F^P7k?3Rxq zZ(xH^Ied>oaY~Eaye2U?MDc{Uun1~(s?*h$JNS9LmGt7dekTtj7bymkBUO^5@rv9c ziyvo>KUbjNg~i)ziq#So#n?)H_1)4UuO#Ntv!H=8ey|RGOSPKt+%HJWR7qV+U#?7! z5`jgKPqwFEvn~F6pn9N5Ea5;A5Y0tzYKQA-12r^Vl#4WiU$?;ZE&<+qBAfF`q zzhhagM7ENLL)eWnLJ(;xA`@ME#c%5NjX@gZ)p6(^N?xTfJR(~f2x6c-F WuY1_pt2_Pp=K_pS=18)h8~zWbs|9ob literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_on_ramp_sharp_right.png b/starpilot/assets/navigation/direction_on_ramp_sharp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e3c4cee56a7de3cce450a83f07fcb55202ba71 GIT binary patch literal 1551 zcmb7EeK^wz93Od^X=80txm3S0QVx~$(7WH{ZOdDmDT|#$Td};HNp5Zyn{vBRxk%bv zXob$pp-^U(RLon#B=bnxIl~&7xZOR^Jx}-7J@A2X%|UkK{<4R+ZMh_+)tpUa0txn;o-}cX+Qzp(vWt$)}GU%UIuWv<>Jf zx?e_bXfWub^9K`TbN3$j=lV*Nj@Tz?A^wPwR zuvKIPKa(=aILTn=9{+_BR>%u+S590Uv-Kx4xTW$ar+R#I6;rk$1Q7*0x(JE_28J)| z$Ind9Hv7$piJ;j@0xHU3u+PFPfFZXN#y;>gV)xa4WQWaPER{835GED!ae?C>A|1fC zsv?BdqDbU776q3&AaCs^nhV6u&hKkM z5AB_tdww+KR^m1XWF#ZWC(5GZV4*V$5Z$v^dq-|&$o4E%IU}zO_C0D>20QVrD?CGy zSNgpvqS!@N}5 z#%Ek-aQ3v^`F`wu?L#T`@HFVsU9!4H*=7Ifl;${)Stq6~&t_Ywr?r|R_Qc4?1=~2@ zM`m#^Td36(nuQnXv8&23Xrg2-x%a%)PJ-AI*V_uTzqB*=E?6}Q79-DI$kp$9a(f=2 zvQK~A5EqUS!ssQ4Q@Ym=YyEV$aT06+s5kT9+!yS^c5_l)XKiqufq*Z=FHiUkyr~3y zQoFeuN3f+vR%k!c?WEXk>^xsDSD}0>PV>itFS63oa}J89EE&ANm*z55n1G zL*r4-sZQ7;PO9_S6+r>JSgp`TuEnD~VLZ}}x7v`F*@ad1bBs#2daZ6|(wd=xD7lR; zE_EVz_3MZ#h!b`KpriVryL5guefU_dO5jq{de}gFO=ZKHEbH$6r<9sEzpFE5P-bAB zFvdnYq<_SudF)(O3iO6OF@IB+)&maL>t3C4J5!HWGCSvHdMZOwrRc(D9%DCCa7a078fj_9=FVW!t|NjSrta^YJ$dv^71v9X53y7;4TRV9LM<-0O!S98_ka)FR--p$H*(I&$YN^{laaWA^&#_v<-EeHR2-Khu)uSPdrqs z%R4_kOFgzOFZ@OC|B9V|JNmA*_TRq#A|ZB;P0O1L2X}oatX{Wli_nLn->#`#KM(3} ze;)s$;%&vVZ>m;t+ID&Rfv+pxd;MEuvio=VrUVZT~-`@|9kHuauHf8C3urD;jug$lQ7WE{R8R_ENsB1nK6-!NoyQusn?w$u(EV}!t(|sFPUhBzqmM7|6koqS zQY}vI^yd6|dEf8Y=$ake`Q&BU`Ow73m;*7N3U;qvE;R9TQrm17n`2@BEFI?EdH7Dm z<$IC#gPE^FM1=l3cF4|@*`)Krw&P8?sBwtB+O0QoXB>r?sv7?Yeez$Fxaw_pMA6H= z|1#WlLN=VOmY6u@-rnHVY)70GzWgz1nW>V}A-&`ScVXKhh14R>Bse^mVGt-SN)PFm6r%Y&UJxM@1)+;&yW56O@W<(c9|iO;O!eu1cJ!0T-+CuOctIiHwC5+gYjanl%dH3>VEM%0>FVdQ I&MBb@0Nzi!kpKVy literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_on_ramp_slight_right.png b/starpilot/assets/navigation/direction_on_ramp_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..f8ea3800e880fcf640fbfec6f849308a49bb5ac3 GIT binary patch literal 1346 zcma)+eNfT|7{|HtElsdRk|qdPtNBt3O`D`5zTpy6Q}d+=Wy`kIA|>C_siEh~R))iF zDK^y7O8HTiDJd?>G^K8#35r^&nMy>8hzpRh-R-X3?T>x#`#hiL?)l^S?#M1S#3=sQw~_?vAxT2|QmCA+H=0tl)8Jy1KcSljM*lEvYo{7yv5sCD6}c(9F0?#y#Ide_mY14t^bS{677We~<($2Qasz{dt2zX1~@ z+hOxA&ZV=j-;l1D^dptohY#i^A9Ffkf4UevfuyP5lb zr4hJk)fkI;I9q+wSudPY@uf4pL3dF;pCNz?EDT3FO=Wk=2QzbD4=31NQ9rUEbk+_n zHTTZ+ObU8ltAyi}6%wbm#0zT|G2B)?Qa6Y~W#=hZx=l=C=Qu0zcz}Jm-BdICKXR$i9ce!drX9=#?L+#xsNKXdsjgx)9-jla? z*pAi!T%vTn-y0=;!FL2+Y#Np=3v*+CP|9vws(86?SZ?haT3S%H*Ij|bxYa+?f`}pL9Pqj4CrcEmDGZ=l{$`*^}ja%crrq4P^p_lfgj)sK7T;R^f9$C-X z!kIp&C!`Nd(O^f!@8QPCs`r6$dG5K4PQ6;6jQV&=J30t)ue)~jYYvy4%Z~SdD zZMp-93j0oUkwQVPW5b_iAc=hi5Mx0_;56^}hFjL`Es~VNJI8mgBBSA=&A~9&qgkpJ zaP6yOI>`a-9=_B1D>Paim*r5)_*!_!V*4cu5#4nSj^6tu`|ZO;+yzxp%N*HIH09 zc@6s&Zu?WWGt|d!WsLqX2PL4mPq;P%^Xj=)PFX0c+wn>6^uabSmE{zU5PmlNDo}7h Ks6Pi!F8mXYqQ4LT literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_on_ramp_straight.png b/starpilot/assets/navigation/direction_on_ramp_straight.png new file mode 100644 index 0000000000000000000000000000000000000000..a01045ae6a2b586dfc374fb7e34e4adbf78a1180 GIT binary patch literal 1063 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HlU>(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_rotary.png b/starpilot/assets/navigation/direction_rotary.png new file mode 100644 index 0000000000000000000000000000000000000000..2a5d264bd274263aa718d1c09a680aeeb6d5c053 GIT binary patch literal 1906 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 QGr?cR7^Js*jav}oFK_w|p8x;= literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_rotary_right.png b/starpilot/assets/navigation/direction_rotary_right.png new file mode 100644 index 0000000000000000000000000000000000000000..32a6b2504ba9d91a8acf885e358252574ad2f77f GIT binary patch literal 1743 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 literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_rotary_sharp_right.png b/starpilot/assets/navigation/direction_rotary_sharp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..d15cbee00232cc8d0dbc67b827638d223a1eb7d1 GIT binary patch literal 1855 zcmbW2YdjN*8^=d3aa@Mj>EgCDEaaAZnQYiGx7_-KkYS>7%YA2&irjW`ztnLwtiy^B zb6JEUS`B3jHP>wCplvR*x%{2~+y8m>|9+n5`M!8wJg=V5FWcSKQC9kxGynjQMLNMR z9(d@VK78n4R@}SNc%UeElo#T_bUK~IVy&&M@pwEwpTE7mEf5HV|7GWY*!_Rm-`~GP z@CF~;I~jk`)e|5g0|e<9TVHVY^g~C*rex$6RuUT8ItPZSw9ky0Io1kKF<^WS0FVeo z!tK10s#dBPB{haXSfw{mOgzyeU9gX<0t8<#0Y*REoWP1GhqKL)r!rsvt}bQ={I}XO zuUNca>L{AI5F>?kR#H`ve4t8Uf6WdrC#S5e zd`#Dnq7*^NmtA<whgn(v8c*}AZYe%o#j&@gDs`t>zX}fR2%Z1ZhkZ|63bDT&KYp$%nS!gc$3v}R z9xVf_2h#d^5_2_iV$uHkI&wuv9z^=xZ;!CSd^glkX3SjgP_Z_DtoCrWgdr4_X*i>P zlCb?PGc&G}0ExfC^fggY=*EC#x9jI5p+UvT{$j^qF<|gsIbT9;+eaK|?$V3_Y1>6_ zdA03?Op8O9F9L3s$b=`Rm>o*zk?>25%MLS_9yp%_6QxLue-Ej5IYEVZ=b&?)PY*ifvc8U5lv571kDP`5BZqz&+8VlxZdXp&PT*V@Palc1 zRC~nLr_fsbOrUbDgcEqn8$E~(QahYK&m!(cks;7(a;YKkN* z?y>gXm1VcDmKe5|fC@puvESw@|wgK+i--9sJdU3;5@USYKP$?GAC zJ@daBmP4uQoyW#1a*IdU?P{{gE)vpZZ2_myX8sYP82(|R z>=T@aHS!%`gfR0C-~T-|)RcU?cX7yy()^?hmHT%AC;R8}Af;eqM!33^-`>?D!A8Tv z=?o!rBuKg3teGqS@|7*$)-VTEae}vXm*n&!2USL7CH*2aHG#izS^fx((!H5KM3f3h z$v&^NWZD9EK*IN=4>b)_(%dH4Y}9Xdh1cdFY~3+3_z=WrBcFI2*n$wau!rl3 ziZ$C{EF>N{4D?>^(;N$#n>d3gW^l6NQF0Gx{B!aiXW{-})xy>dw&!oIy+>hFguB)0 znOkQpqrk)2xtLXS8aAc~t(GiE)5>}vB7_fTTzq`P1X-#?y?4X|}mDape0fY&ze zpo6oszJ7Z-&}hcZAyRuuU47qJLY;1~PuXT<)-k6JcrJEL)B-UIGY*8`!WAdAD)1_i zafrtGphBpEpT_7wQX!P=vTuKtMwL;?ycA#UX$S%haZdX5^T(yduSzH;w2q@~&*1A~ zqko>67R+v2YHD=~(j)|LIQ=8;(uGTJx9BweL|iw;8jK6lI0`e;+luZS^n(A8wWNvY@Ab literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_rotary_slight_left.png b/starpilot/assets/navigation/direction_rotary_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..3838e720a3553a713f012ce6fcd1de134edeabd2 GIT binary patch literal 1699 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 ehvnaT^ZvjcA(u{%y1l;p9{?9efoJ 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 QGr?cR7^Js*jav}oFK_w|p8x;= literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_roundabout_right.png b/starpilot/assets/navigation/direction_roundabout_right.png new file mode 100644 index 0000000000000000000000000000000000000000..32a6b2504ba9d91a8acf885e358252574ad2f77f GIT binary patch literal 1743 zcmbW2dpHw{8^>2FnUUKQKO`HAVhS-$iZ#d2TsCsc$RQNJ&->E<`KzVY>M z$o>^_xg5^8EZng)CU|?E2kZl>X+xl9)(9lp2Y2a*gzH)4VoF^Tvzs$CI{EH{aB1~R zMHfCC0N6Y4igNO~Mp>+yt$b*xmhI1MZa0T<8AJFbx$c2|$10(Q_w57~VqRwzEp-=r z=*0F{!~N<15VeYZ%KXteReZuZTJ-wE<_K;toD$jHf5 zhLy$Cop-5)0g)Sf5&j*G>U0U$b!t=2yvcRvc;b=ujDlseX@upNQ4GMP|WzKp?S!^2kt&V9&LNfCW)jQF}oi3(cPebyrr{-o!sO3sofPPObjM^J6{`? zUMsDd>m|rhla5}KO*#fh9ykO4{av%0^%5rfl8(nm&7s5C7y;_`OyZ&q8p+DT&_xMn zE8U3LQccQa8B6tIF0oNCd7?`2dUGXvx%B1jbScydaUUHZzYE|m223Ai(mAaOZ%52R z(0%8Xw!+T!XEw+RAKN!Ll|WnpCMizkgEuEhi=zcgV81}pf7ox6s2`~l$%%Qi=T|JWdGT+UsD+iEAyjj<~mcHugh zi~TqscJuCqaSZezTc+s(n`Qt$Ie$5y8&ZuNdk(9*5PUuJ3k+`5tOcC)gFfAy$ofs!gb*i96p~>B$HCp4g;Tao(q8|boTn4Rm7;DaW zP=;R%r9)6@YoV!#9P3_wZ`L*eTU{gaUEJ9S_o5mj9N6Y5hinS#$jB>F@}`Ezw!LWc zcMEHBU-#3%;e11hw3*XBeoAqqOg#@g?T!Ar1gPlH{h=zyw(?U=!>JUvI+MFEc*NN= z9)$IA{cJ?ig~N6N0tKb#LDUH}z*xgC8zrCS;>=gOm&5x;Bc1^giXlg#utRO}%mLs& zA2+)|1jl1M6RICk@A%6Cr>vcrv(>|^tyBk(x!4kI@~%{r{8|_XrSy9D`$Ty1o-+sU z6rzB<&Ror0m*!Z_gZInoZ${OlYP4GQ8gzYdOY!LJJZp9#*|O1Cwt~L$nD%>@wcTAh zh)E!n+J(ONf4Z%4?R%<=P~VS$SkGVR>b!M(jpZxX5g{UdiJ!Z}QeW@<`rX zYMxh=B}`f>k0h^}jOOjG`}y2I?&s4V_xm~L_dDl&&gXOfJ8{;yUw|SqA^-pYXl`a= z%k%#4Da6myoESni&)lso?Xf%`8yj0(Tx7G^91e%eR@saBPVdB= zND43^U(4$o(}u!AQ|x!F%bO&wYN_64MyM0bs3MuWvq#uAnczj{m7n{HHkB)45H!!6 zFAQZ=;H~_}xnDI$&z{o0c=np|J3e!-owwY$pwH-~1v1?kzvUslo=D~vkDmnYR))Z7 zqRv4D9cn94>MM#&NB=AsJ|u-pdnNf)ro&F8P6{}bZuTOy=}pc1>>=q%yQ<4+AGcS7 zKN=4I0ilCVwA4sHjPxvsF zBHnf^RlLbfX0{##j~2@QZ9RuBbYTAZWBj0AW1z0r+D*6;1jdI$v_44JN5^ZM&IJkh zs;Y4PJ1bmr_@fWZuDt06Jd;1?!2#NmCGSF`ZyQP0WK-18K#Z7Tgw0C|YU&!3Zxm{j z4b-jR@cr7u-!r8OT^1eCh;4o(aC$lF;B%eQo}yV4dxU%?si*8=U16N04OO#~uJ_B0T@tC(=#fMvO@`_3yee$kIgbI)MV z5x8;JQA2y`eL^X&%GCdow2y|iY~pHz-$PG1YN*tQYQoyeMO>1n2a04!zxl*~d1REXZPX585xiK-cTsEZ6Dtdshkt0XVS*Y2h_-SJ5D7$M`%$>Ft&?6TT(^ALd zoX#qlcs!4-+Sj$JBS?)Q@yV?Z=xA{p7$uRx1lHIG(dHxdJ`>kQ21xD^D^m)otUdj{ zsHlGTbfzq}2%{T|(S`@a1nP=`U{vAA_HUO;1O-z(5XmYXy=0{LX1;-an?$1^e@X{X z*i})O-DNoIGen-qAd!&bPJstDcy`^Vx$sI{7H{WvBX|D%4n``rkuzw8pIPWK6zIk6 zoSDZ?HCzZzeUIT)ZT@ovxiweH-V0A+7C|QfgD8*8KVzR^81J8}=K+y4|?~3vx(_S8}@;?%cbxrAbvaRUg?F zxnOxTcdjG(ahBiO$OoIh<_pq%d)Iff^b%T->o42Upy`IP>wP1M0n>ZRZsqt?2!4=@ z1U}K|Qd=Fpm4S1jKe2ndBQrk{>>}*TGFymls|o2?9#3EyoLHIN#!uBcDTBY|-^rhE lWz2mwQ2Wtqi&RKnm51GZp)!@sV(|Vez#NM+sWEnq{2Sb^`w##C literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_roundabout_sharp_right.png b/starpilot/assets/navigation/direction_roundabout_sharp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..d15cbee00232cc8d0dbc67b827638d223a1eb7d1 GIT binary patch literal 1855 zcmbW2YdjN*8^=d3aa@Mj>EgCDEaaAZnQYiGx7_-KkYS>7%YA2&irjW`ztnLwtiy^B zb6JEUS`B3jHP>wCplvR*x%{2~+y8m>|9+n5`M!8wJg=V5FWcSKQC9kxGynjQMLNMR z9(d@VK78n4R@}SNc%UeElo#T_bUK~IVy&&M@pwEwpTE7mEf5HV|7GWY*!_Rm-`~GP z@CF~;I~jk`)e|5g0|e<9TVHVY^g~C*rex$6RuUT8ItPZSw9ky0Io1kKF<^WS0FVeo z!tK10s#dBPB{haXSfw{mOgzyeU9gX<0t8<#0Y*REoWP1GhqKL)r!rsvt}bQ={I}XO zuUNca>L{AI5F>?kR#H`ve4t8Uf6WdrC#S5e zd`#Dnq7*^NmtA<whgn(v8c*}AZYe%o#j&@gDs`t>zX}fR2%Z1ZhkZ|63bDT&KYp$%nS!gc$3v}R z9xVf_2h#d^5_2_iV$uHkI&wuv9z^=xZ;!CSd^glkX3SjgP_Z_DtoCrWgdr4_X*i>P zlCb?PGc&G}0ExfC^fggY=*EC#x9jI5p+UvT{$j^qF<|gsIbT9;+eaK|?$V3_Y1>6_ zdA03?Op8O9F9L3s$b=`Rm>o*zk?>25%MLS_9yp%_6QxLue-Ej5IYEVZ=b&?)PY*ifvc8U5lv571kDP`5BZqz&+8VlxZdXp&PT*V@Palc1 zRC~nLr_fsbOrUbDgcEqn8$E~(QahYK&m!(cks;7(a;YKkN* z?y>gXm1VcDmKe5|fC@puvESw@|wgK+i--9sJdU3;5@USYKP$?GAC zJ@daBmP4uQoyW#1a*IdU?P{{gE)vpZZ2_myX8sYP82(|R z>=T@aHS!%`gfR0C-~T-|)RcU?cX7yy()^?hmHT%AC;R8}Af;eqM!33^-`>?D!A8Tv z=?o!rBuKg3teGqS@|7*$)-VTEae}vXm*n&!2USL7CH*2aHG#izS^fx((!H5KM3f3h z$v&^NWZD9EK*IN=4>b)_(%dH4Y}9Xdh1cdFY~3+3_z=WrBcFI2*n$wau!rl3 ziZ$C{EF>N{4D?>^(;N$#n>d3gW^l6NQF0Gx{B!aiXW{-})xy>dw&!oIy+>hFguB)0 znOkQpqrk)2xtLXS8aAc~t(GiE)5>}vB7_fTTzq`P1X-#?y?4X|}mDape0fY&ze zpo6oszJ7Z-&}hcZAyRuuU47qJLY;1~PuXT<)-k6JcrJEL)B-UIGY*8`!WAdAD)1_i zafrtGphBpEpT_7wQX!P=vTuKtMwL;?ycA#UX$S%haZdX5^T(yduSzH;w2q@~&*1A~ zqko>67R+v2YHD=~(j)|LIQ=8;(uGTJx9BweL|iw;8jK6lI0`e;+luZS^n(A8wWNvY@Ab literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_roundabout_slight_left.png b/starpilot/assets/navigation/direction_roundabout_slight_left.png new file mode 100644 index 0000000000000000000000000000000000000000..da1b1127051a19deaaf9ca1fd7faad1170bfe96b GIT binary patch literal 1702 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 ehvnaT^ZvjcA(u{%y1l;p9{?9efNtYng1f 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 ByXgP` literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_turn_sharp_left.png b/starpilot/assets/navigation/direction_turn_sharp_left.png new file mode 100644 index 0000000000000000000000000000000000000000..dd8a4301db6dbee6bb7df86a7a1d04dc813886af GIT binary patch literal 1546 zcmbW1Yd8}M7{`}eBf?m@h8<2q%COusnOkn*n6QzJ%6-gzv80p9wGtss(S+7^D2z&_ zwv)s$h11_5OH{Tcy@M{&*!hKtOx`Gp-}k!`}g(r^^L#u`@gmMpS8Wc z{l+m)M|49A@8jtUklLl7qVuB>%;C5%3KNMZWM95kd8eVJ<9QEz{KJAfxl^<%Y31q& z_e-r>yvYo^a9Gw}9aJGVYW;OPYZTTiHluSg?_9t2g~l?_C@W!OwN5|p_CLJjWoPWa zuo(OFeau#X=TnSx4&~^{n~_A0MKV@JN>Be=UmfpdVP8>n^5LKf3posP4({*2yWr>^ z`V0IN^hfH)Y-zPa3aI5ZJrj2R=XX2%D)@G#@gcCfHrP(ira-Z2Mp&k&7 zv4`q57KB%nRP8biwuawq#b)j!rnr)9W}zzrP6^eMCdw^?JFcQNECz;*O(*v2C1lDz zVsd6(kcQI*4v^7An#@nj%@o5RTeu7McQrZR*^nS}gK=*M$fqc?Wp@AFI4>kJYEl7| zwu{Tl@XC}5OT(GfHZnO-2tVXx2Ea?>p&^C=0-w#FZ=I|NG@sX-cm9QBc6-U-P^rB} zz5Fq!T6(~eK59*DptPPvH>pmPoM`3Cpb6J4A&|$PQ>nIPG`!vcXe8oe+gLUAQK4uU zK%WVSqSbKSe6Ztc@saH?3zTbKaG-c>K5~s`9cjmP^RDIFYCAJP$~W*%W;_~W034BZ z%mMqGsv?!&F#w+TaB`^aP&;a0W;p;(V1_tI2+8N$$r~9_#Dj~{xdicJ$*^bXi^`l@ zhrMeOjuBnOi|@L(6x-$`gD-5f09&ra3~`@~n|fRoKV|K2FJVM8w+nM-jCohw7b2jc z-4QxF)7K`+i!YZh=MxpxACL<1;X&o+{3Otlb_;mb6b4AiBzlu0t}((MQoTj(c9ccT zZJ$1_jdCT)y2GiNrv>-y8CO8`CbDN?W4kv@=am`XYW z1X2~7PNT`kCQt9FF<)tV5j5J4=s))=D<03lT^{L?)&?J6&}nv|fM%u?%c)q$S6%VR z+3eE%TnuS4oR7S{)drl;b@t%3f6oCXSaq+Z5ZooydS$&BAVr+Ad}VMz-^ABE^7SX3 zvnSFJJU-o{TpmHoTOmHn7YgcApBacDvt_l_+k$5U?4s~{W?Z>?mTWe5ehnmSfJU6A9O6DZxVfJv2_R+hF@NRlz^ zqvzRIl7Ys}WFMJ3xtJeb_dW!sqOi*J*5$Ml2U!=boJxvKs}7aw;RL9h?rkw_YW!42OM>kw~?i1Mw(z2PQTrAH*nSmf;*qKEFr5iMH1OXUBy zJ%`cebk7gKI90!`pktgy!SGbt8*^T#G*URrMdZ7zGiaL|CYnN|GUCMFzJ?d>Fr)w4 UAJ#<^{aXOQ72)YfbqLM=0~U1z7ytkO literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_turn_sharp_right.png b/starpilot/assets/navigation/direction_turn_sharp_right.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e3c4cee56a7de3cce450a83f07fcb55202ba71 GIT binary patch literal 1551 zcmb7EeK^wz93Od^X=80txm3S0QVx~$(7WH{ZOdDmDT|#$Td};HNp5Zyn{vBRxk%bv zXob$pp-^U(RLon#B=bnxIl~&7xZOR^Jx}-7J@A2X%|UkK{<4R+ZMh_+)tpUa0txn;o-}cX+Qzp(vWt$)}GU%UIuWv<>Jf zx?e_bXfWub^9K`TbN3$j=lV*Nj@Tz?A^wPwR zuvKIPKa(=aILTn=9{+_BR>%u+S590Uv-Kx4xTW$ar+R#I6;rk$1Q7*0x(JE_28J)| z$Ind9Hv7$piJ;j@0xHU3u+PFPfFZXN#y;>gV)xa4WQWaPER{835GED!ae?C>A|1fC zsv?BdqDbU776q3&AaCs^nhV6u&hKkM z5AB_tdww+KR^m1XWF#ZWC(5GZV4*V$5Z$v^dq-|&$o4E%IU}zO_C0D>20QVrD?CGy zSNgpvqS!@N}5 z#%Ek-aQ3v^`F`wu?L#T`@HFVsU9!4H*=7Ifl;${)Stq6~&t_Ywr?r|R_Qc4?1=~2@ zM`m#^Td36(nuQnXv8&23Xrg2-x%a%)PJ-AI*V_uTzqB*=E?6}Q79-DI$kp$9a(f=2 zvQK~A5EqUS!ssQ4Q@Ym=YyEV$aT06+s5kT9+!yS^c5_l)XKiqufq*Z=FHiUkyr~3y zQoFeuN3f+vR%k!c?WEXk>^xsDSD}0>PV>itFS63oa}J89EE&ANm*z55n1G zL*r4-sZQ7;PO9_S6+r>JSgp`TuEnD~VLZ}}x7v`F*@ad1bBs#2daZ6|(wd=xD7lR; zE_EVz_3MZ#h!b`KpriVryL5guefU_dO5jq{de}gFO=ZKHEbH$6r<9sEzpFE5P-bAB zFvdnYq<_SudF)(O3iO6OF@IB+)&maL>t3C4J5!HWGCSvHdMZOwrRc(D9%DC0O!S98_ka)FR--p$H*(I&$YN^{laaWA^&#_v<-EeHR2-Khu)uSPdrqs z%R4_kOFgzOFZ@OC|B9V|JNmA*_TRq#A|ZB;P0O1L2X}oatX{Wli_nLn->#`#KM(3} ze;)s$;%&vVZ>m;t+ID&Rfv+pxd;MEuvio=VrUVZT~-`@|9kHuauHf8C3urD;jug$lQ7WE{R8R_ENsB1nK6-!NoyQusn?w$u(EV}!t(|sFPUhBzqmM7|6koqS zQY}vI^yd6|dEf8Y=$ake`Q&BU`Ow73m;*7N3U;qvE;R9TQrm17n`2@BEFI?EdH7Dm z<$IC#gPE^FM1=l3cF4|@*`)Krw&P8?sBwtB+O0QoXB>r?sv7?Yeez$Fxaw_pMA6H= z|1#WlLN=VOmY6u@-rnHVY)70GzWgz1nW>V}A-&`ScVXKhh14R>Bse^mVGt-SN)PFm6r%Y&UJxM@1)+;&yW56O@W<(c9|iO;O!eu1cJ!0T-+CuOctIiHwC5+gYjanl%dH3>VEM%0>FVdQ I&MBb@06s*zH~;_u literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_turn_slight_right.png b/starpilot/assets/navigation/direction_turn_slight_right.png new file mode 100644 index 0000000000000000000000000000000000000000..3e21cae11ed5209a7f63f7352d7ca2c4ef5b0b14 GIT binary patch literal 1347 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3PvVgr0aT!HkZOP5}}c=7)I`_G?0 z|M>Ca7a078fj_9=FVW!t|Nrx>eU1VxkShuD3ua*D77$l8ws!Ikj!w=lu5Rj@JbTIN z&ASetxpL?6>mzF(>N7B~lzX~3hE&XXJLl%K#Rfbsk(=NDcKi3=cy@`EtojKy>pAO^ z+`gA4^sQQ$<0;muSv3bA5XEv~P#B&%EZJ^m3=FqQ-iAN!e&YBlp)Dl5e5}nm+IH-1jen!;$a5 z@3uc@z9+1oy=3!gcBc<<<{if$Y8p0Q_ig*_pePe({xY|@WkbbX6_rxOPrE$LzQ-O~ zu_tem&z~h5D(^0MuG(_`wf`QoYPa?FGb&#weElUme`|I(-!;c)kIRzQKaUGN#UQ(G zYUBM^-mkxQPVadwDZ9RR>3qJh_3HPg>My@;{C`o)rPq5KCYigk>k3?2n*QaNjRX6_ z>ytMeGn;#Tv-1Q#tM$(p<|Y`e=XbU)Nr{`!c1q!MRZMVgPMUVMd{GaZxg>C8n@Zg7Hii(G;ZOfLawn{A6u=DZWcQ$4g&p-K2ZSVNL zYqOR8jj9DxugTtdeQr<6`9n4*S3Nd{S*$ zee>ZL_D9=$w}*fF;?5X7A*ffr&(vM^#hB+mTg^sD!a7x>n_{k_-pt7?8iRnZHtx9QDx4?ezPT|?aVIXC2NoT}swG4IXu6yu(Mv32=rps3A+!oPFb_UkTL z_S*S(gv_IxU;n)IeY8h!yZhd_H76?U6XVuTaV_6tFQ#`PZu)Y@Z}n~RPnfUo0pPfKqz{iF@ zEryLD-@W}TCX^j!x|6`|=u=Zz9cA(8(d+$^k0w473)s)_NpOi$F3PaPp!@`z0o4S^2||x zT^5DjkFpmXTNR$}i`7|mL^$(S{`Oc8^#yb9@GouJ+srFsdG*y2ftQ^npRP`_aWdw4 zci4V&mS^cyF2_YqHv$xMRtT7da7b&l@QNO4<4SZEdSrj!r2)uj-LMdwywt-NDQER+ zjqjdhw8~tzvD(`$@fBydc`>$WW z{`m3Z=g*(Ne*O9l1AkD#U!uYP|NotiUB3skK&~XnFPMRiTR=+9$lA#}I667Iq`IkR z^6X`6Htsok`tt3kuYYqzLC#x{pH2;BU>XL&_Txqf=~ zdqcVH)8gOXE4Il}3s-*cDQEm^zH?vg`$)Nq_V=1jT&tepo};?q!@OmC`86v)&s)BB zdl8=|+dbi}#v1RMPON)v8!UbIZY|%$sow)~*Q~O1S#~ej)ck7Eo(CTbBO(?4%f!9; zal`tBrOUoO?%B_@r#Yv*vyB%1T){VS~I3&J9oKW$hadM~)R;kuS`^*`w+QK~w= zIS00$x;D>_C3+R3{)Y~?gHvm;Ti+P*pS?43FC(X(zOWKI2b=}249>Ik3_OTrAjg{58AP70WH zgCT3`luJjR?bqLSpY!yd?5S6PoS4-r)78wbM=f>COe$UzI%|sBw#m0YZj1!-R)G&n@|RrRHVM{Jmi-wSCQ|iwFIkx^st37A*nM9sFaS!-6;OQ^D1 zuCIPtGht=e$|-6`gKi%eYR-6V7reIU`}UB`R`yBF8n5k6=LOZ7-g3Ra^oD{*>RtKd z{_16QADFkBo`2@%cy8Ij{9hlwtTf#&zhcb?hsz2Ncb)&d?bgNj!cp-L8=pDmz5X}j zrGQP$`|^pRav8!;HofEDEqZ0YPZS&D5rqs17T)Fsi2^1(O>K@B3^=6N91qh<&^MlQ z(o;SY|K)df%KT%_4LSAp%L02=wRJ^@Z9klU+Npi_{F)VagnK(6;9rBh_jJ$Mde?Wn Q0cJ=BPgg&ebxsLQ01@OIpa1{> literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_updown.png b/starpilot/assets/navigation/direction_updown.png new file mode 100644 index 0000000000000000000000000000000000000000..16d0979f3ed040ea1036a8a737d609b400160faf GIT binary patch literal 1327 zcmb7EeNfT|7{)X;EXACqWlANup_w__G{}=OO`T{eSmbAANUd!pIU-F1G_>*qV-{z> z)DTUC=YPvkySpOj0bQA6$xgNq!Wg-R+P5+U>dbeV@Dc`Qy3wy?fuv6nxwg z=n5zV0$CEjJto!84?d-YQ;?}k(5n!;$}C0kC;<&AZkyv0@-F=vx691i|aO1)C3pxmWDwa!{a45mc zf4gY37Ktq*{r*)FZA4nNn`ddFcwa*69n`37${oj60*b%Lqn3E(91}-A-E8ffhm}n_7iFUU;p$V<`)S`aOGQhN`jr>J5O+?=TyU7t! zD_~dDr~uscIziDQhnBXDNc)uqHs>^^N6nzUm`1aoQ*1;fDwc=elNIA*%k?` zte-!ALw;S|{%JP%hocEcZwf37y=sOF+aZ+kd&l>CJMz&{ZXf0f3>p1D(2xHnWK&yBLYOW$K`-GaJi`VdtFf7t0x6Fhv$g2 zYG+)i`GhiuDI3XIu@HBc(UgaK(giQr2}6gtu2|-@#Ent05ZCh`?GYFG&po%u{ECyk z$x7|!-4Xb@xo*V|9Tz@yo2k35He@>LtQQ9xRd~1Q9j~2kB)|M?GK$-fqK38$BGm(- zW|B1zC#Wtge2QOvkdmuar@lz4FFjVCQ;ESezmuHaa8Gi&mKpXaBeSM-)Q|PF5M7B0 z8Qbhx6paZHjJ*c{M=rfuW{RYCj`_#{<_tX+@!B`LncT?cIjmoGcIf2!eVzHP96*wO zz_}ds)d|Sw0bsI%?u_s7b?6{}DFimi>CVfAz6cRnb{#luraO-a<(%lp2v55BjjI;* z-m319561TAZ>5V%RfVe?fMAu6Xz3MEr@g7|B#HJ>3cZHb_e!BMv|fI|n?|`arB11`pGPRE)kDQ1bEdcQ lEFttYNsD{J7Wb6t1GdBf+Nxa(#_j(I62A=}Bi@qB_!}`=u8IHv literal 0 HcmV?d00001 diff --git a/starpilot/assets/navigation/direction_uturn.png b/starpilot/assets/navigation/direction_uturn.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd1b91777ed8d3c487e188c945383482b219c43 GIT binary patch literal 1780 zcmbW2X*Amj7l#vDB4TMe!Kqq8(GzNE6(!mcX@yBDme84?A#Erv(uP{PF_sQ#TD5dS zsM?Bu#?n$tLfT=dWsDk3YbjE-R5YE^O3)ZHALhL8$M=2C{oUuwJ?DPA_XpBRcXikv z7zhMX_rT+PcKrPBKoxg-L3%K6M>G<_@A!^KMn)DF7bOzO+S=Os`npsqmC0lq|FHQF zTmQ|M|Ap=C?GRf+?amq_rq4-Vkcyg?F3J>bhdJR(p+z#2Qdl{KWx!*8SO4hb%v*6P zhn5clsTg_ST>av?D@Dr%r8e+%2&SYIUL1?DS-+mQ%<#icG!n<(ug-npJD1rYt*-}YqocT$4L$Io!im0?sXPxcqnYyx z<0lcTG-SvJsSEqxV10iv_@cHjkv&FSy3l?mFxnGw@>tj4UZ?p6@|CN^Ed#)O0`rKS ziR(^t3v`!N4l_9VG&E{t7g@EMebe)1Y+!EJx07B~v4Q!)wy%Sf-?b-A^76A}p{?U( z@=YfJTi$C|wfdx35FL@V#K@7e)xjWc_BW6lcyn_#Ay+C|TAXFx{4JR~>FvbO6phu>l*_CVvM>m3I z74R>AIGgaX{ax;?y&mXv$8<-)uY*s?dYONs!C!`tWrH#Jv+5;SHCW1&qO|Mc`>8|E zjedzxNX&>C+&5$GzRTzP*A(t1&L)c3KuXIW;qomOT|6EMX#9GG@Cwh5N;j4dbaM+$ zscgDRx}b=0sR=xQGA@UfbS8GQtilgrbDBUz5{rV^Kj3jF+EsG8y9|Mc-a67@0kJp7 z`W*Uy;vV<*3Tvr*hHh1u+ucP+qnbxp$gEaDTmAq~9g>2>7FP=>ov7^gR{0jgDI6bf zj`--LHyNo}a{gCjbgRV%3u%m!n8){c1|`zNqP7@wRbKl{geCz6t$mUU19?BK65DgM zRF}%>mLWp-LVl9eIsIo$O|!p)&KX6S%kbp=456d0r)hQSnWt$Wp*zRohPbgiH^Rdn z_4&bh0ejkH;MOyE7|kC%RRFGqoqMM#%wT^yhBz>8Ag7+Q^J_o|t zk|pO=g~I*#jvvh4on$xUS!(gtYA*O&|P**T3DzPPegOX$7vnpiAFb3go52@ zp6HJ|rlbySV_vAv&IleKbu{V&uT(S7H4F|&uPvcYp-V!7*P_7sRu8@P{2Me1n9v`& z)vCZt2$2*JhA349v>LBMIaUB1ATcdq1?vD5Xi*|Mr4p$s&Py+t*EB4Y;J{F0h$`1d zBb6-B8=6wJEKi#Jdh|E@#yfG9IgvxS5m|_0M3BcA}Zn_hHs^S7rE@)kjnA z1ZbPTU8jUX6Vl07Qq1&Ap$TUgcgK^p)wfQYwR|cnzaUiS;n&MmsPwg<^ZXu~YsWYB z#@lm#W0@n|S1xlW20v_R)W{5DIg2{M%KvfRZqUx^eZ#oxcL|IDQgWi>0Rg E1z#s(%m4rY literal 0 HcmV?d00001 diff --git a/starpilot/common/safe_mode.py b/starpilot/common/safe_mode.py index 86355cdbd..6b9a502cc 100644 --- a/starpilot/common/safe_mode.py +++ b/starpilot/common/safe_mode.py @@ -41,6 +41,7 @@ SAFE_MODE_MANAGED_KEYS = ( "NNFF", "NNFFLite", "TurnDesires", + "NavDesiresAllowed", "QOLLateral", "PauseLateralSpeed", "PauseLateralOnSignal", diff --git a/starpilot/navigation/destination_store.py b/starpilot/navigation/destination_store.py new file mode 100644 index 000000000..8393d28a1 --- /dev/null +++ b/starpilot/navigation/destination_store.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import json +from typing import Any + +RECENT_DESTINATIONS_LIMIT = 10 + + +def _coerce_float(value: Any) -> float | None: + try: + return float(value) + except (TypeError, ValueError): + return None + + +def normalize_destination_payload(payload: Any) -> dict[str, Any] | None: + if not isinstance(payload, dict): + return None + + name = str(payload.get("place_name") or payload.get("name") or "").strip() + latitude = _coerce_float(payload.get("latitude")) + longitude = _coerce_float(payload.get("longitude")) + + if not name or latitude is None or longitude is None: + return None + + return { + "name": name, + "place_name": name, + "latitude": latitude, + "longitude": longitude, + } + + +def parse_destination_json(raw_value: str | bytes | None) -> dict[str, Any] | None: + if not raw_value: + return None + + try: + payload = json.loads(raw_value) + except (TypeError, ValueError, json.JSONDecodeError): + return None + + return normalize_destination_payload(payload) + + +def normalize_recent_destination_entry(entry: Any) -> dict[str, Any] | None: + if not isinstance(entry, dict): + return None + + place_name = str(entry.get("place_name") or entry.get("name") or "").strip() + if not place_name: + return None + + normalized: dict[str, Any] = {"place_name": place_name} + latitude = _coerce_float(entry.get("latitude")) + longitude = _coerce_float(entry.get("longitude")) + if latitude is not None and longitude is not None: + normalized["latitude"] = latitude + normalized["longitude"] = longitude + normalized["name"] = place_name + + return normalized + + +def load_recent_destinations(raw_value: str | bytes | None) -> list[dict[str, Any]]: + if not raw_value: + return [] + + try: + payload = json.loads(raw_value) + except (TypeError, ValueError, json.JSONDecodeError): + return [] + + if not isinstance(payload, list): + return [] + + normalized: list[dict[str, Any]] = [] + for entry in payload: + recent = normalize_recent_destination_entry(entry) + if recent is not None: + normalized.append(recent) + return normalized + + +def update_recent_destinations(raw_value: str | bytes | None, destination: dict[str, Any], limit: int = RECENT_DESTINATIONS_LIMIT) -> list[dict[str, Any]]: + normalized_destination = normalize_destination_payload(destination) + if normalized_destination is None: + return load_recent_destinations(raw_value)[:limit] + + current = load_recent_destinations(raw_value) + updated = [normalize_recent_destination_entry(normalized_destination)] + seen = {normalized_destination["place_name"].casefold()} + + for entry in current: + place_name = entry["place_name"].casefold() + if place_name in seen: + continue + seen.add(place_name) + updated.append(entry) + if len(updated) >= limit: + break + + return [entry for entry in updated if entry is not None] diff --git a/starpilot/navigation/navigationd.py b/starpilot/navigation/navigationd.py new file mode 100644 index 000000000..955960de1 --- /dev/null +++ b/starpilot/navigation/navigationd.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python3 +from __future__ import annotations +import threading +from math import isfinite +from time import monotonic + +import cereal.messaging as messaging +from openpilot.common.gps import get_gps_location_service +from openpilot.common.params import Params +from openpilot.common.realtime import Ratekeeper +from openpilot.common.swaglog import cloudlog + +from openpilot.starpilot.navigation.destination_store import parse_destination_json +from openpilot.starpilot.navigation.route_engine import Coordinate, MapboxRouteEngine, NavigationRoute, RouteProgress + +NAVIGATIOND_HZ = 1 +REROUTE_TRIGGER_SECONDS = 3.0 +ARRIVAL_CLEAR_SECONDS = 5.0 + + +class Navigationd: + def __init__(self, route_engine: MapboxRouteEngine | None = None): + self.params = Params() + self.params_memory = Params(memory=True) + self.route_engine = route_engine or MapboxRouteEngine() + self.gps_location_service = get_gps_location_service(self.params) + + self.sm = messaging.SubMaster([self.gps_location_service, "carState"]) + self.pm = messaging.PubMaster(["navInstruction", "navRoute"]) + self.rk = Ratekeeper(NAVIGATIOND_HZ) + + self._route_lock = threading.Lock() + self._route: NavigationRoute | None = None + self._active_destination: dict[str, object] | None = None + self._requested_destination_key: tuple[str, float, float] | None = None + self._route_fetch_inflight = False + self._route_generation = 0 + self._published_route_generation = -1 + + self._last_position: Coordinate | None = None + self._last_bearing: float | None = None + self._off_route_started_at: float | None = None + self._bearing_misaligned_started_at: float | None = None + self._arrival_started_at: float | None = None + self._last_nav_state: dict[str, object] | None = None + + @staticmethod + def _destination_key(destination: dict[str, object] | None) -> tuple[str, float, float] | None: + if destination is None: + return None + return ( + str(destination["place_name"]).casefold(), + round(float(destination["latitude"]), 6), + round(float(destination["longitude"]), 6), + ) + + def _snapshot_route(self) -> tuple[NavigationRoute | None, dict[str, object] | None, int]: + with self._route_lock: + return self._route, self._active_destination, self._route_generation + + def _route_token(self) -> str: + return self.params.get("MapboxSecretKey", encoding="utf-8") or "" + + def _clear_route(self, *, remove_destination: bool = False) -> None: + with self._route_lock: + self._route = None + self._active_destination = None + self._requested_destination_key = None + self._route_generation += 1 + + self._off_route_started_at = None + self._bearing_misaligned_started_at = None + self._arrival_started_at = None + self._publish_nav_state(None, None, False) + + if remove_destination: + self.params.remove("NavDestination") + + def _start_route_fetch(self, destination: dict[str, object]) -> None: + if self._last_position is None or self._route_fetch_inflight: + return + + token = self._route_token() + if not token: + return + + position = self._last_position + bearing = self._last_bearing + destination_key = self._destination_key(destination) + if destination_key is None: + return + + with self._route_lock: + self._route_fetch_inflight = True + self._requested_destination_key = destination_key + + def worker(): + route = self.route_engine.fetch_route(token, position, destination, bearing) + with self._route_lock: + still_current = self._requested_destination_key == destination_key + self._route_fetch_inflight = False + if not still_current: + return + if route is None: + return + + self._route = route + self._active_destination = destination + self._route_generation += 1 + + self._off_route_started_at = None + self._bearing_misaligned_started_at = None + self._arrival_started_at = None + + threading.Thread(target=worker, daemon=True).start() + + @staticmethod + def _timer_expired(started_at: float | None, threshold: float, now: float) -> bool: + return started_at is not None and (now - started_at) >= threshold + + @staticmethod + def _bump_timer(started_at: float | None, condition: bool, now: float) -> float | None: + if not condition: + return None + return started_at if started_at is not None else now + + def _update_location(self) -> bool: + if self.sm.recv_frame[self.gps_location_service] <= 0: + return False + + gps = self.sm[self.gps_location_service] + if gps is None or not gps.hasFix: + return False + + latitude = float(gps.latitude) + longitude = float(gps.longitude) + if not isfinite(latitude) or not isfinite(longitude) or (abs(latitude) < 1e-6 and abs(longitude) < 1e-6): + return False + + self._last_position = Coordinate(latitude, longitude) + + bearing = float(gps.bearingDeg) + self._last_bearing = bearing if isfinite(bearing) else None + return True + + def _maybe_update_route(self, current_destination: dict[str, object] | None) -> tuple[NavigationRoute | None, dict[str, object] | None, int]: + route, active_destination, route_generation = self._snapshot_route() + + if current_destination is None: + if route is not None or active_destination is not None: + self._clear_route() + route, active_destination, route_generation = self._snapshot_route() + return route, active_destination, route_generation + + if route is None or self._destination_key(current_destination) != self._destination_key(active_destination): + self._start_route_fetch(current_destination) + + return self._snapshot_route() + + def _build_progress(self, route: NavigationRoute | None, location_valid: bool, v_ego: float) -> tuple[RouteProgress | None, dict[str, object] | None]: + if route is None or not location_valid or self._last_position is None: + self._off_route_started_at = None + self._bearing_misaligned_started_at = None + self._arrival_started_at = None + return None, None + + progress = route.get_progress(self._last_position) + if progress is None: + return None, None + + now = monotonic() + off_route = route.off_route_distance_exceeded(progress, v_ego) + misaligned = route.route_bearing_misaligned(progress.closest_index, self._last_bearing, v_ego) + arrived = route.arrived(progress, v_ego) + + self._off_route_started_at = self._bump_timer(self._off_route_started_at, off_route and not arrived, now) + self._bearing_misaligned_started_at = self._bump_timer(self._bearing_misaligned_started_at, misaligned and not arrived, now) + self._arrival_started_at = self._bump_timer(self._arrival_started_at, arrived, now) + + if not off_route: + self._off_route_started_at = None + if not misaligned: + self._bearing_misaligned_started_at = None + if not arrived: + self._arrival_started_at = None + + return progress, { + "offRoute": off_route, + "misaligned": misaligned, + "arrived": arrived, + "now": now, + } + + def _maybe_recompute(self, route: NavigationRoute | None, destination: dict[str, object] | None, progress: RouteProgress | None, route_state: dict[str, object] | None) -> None: + if route is None or destination is None or progress is None or route_state is None: + return + + if progress.current_step_index >= len(route.steps) - 1: + return + + now = float(route_state["now"]) + should_reroute = self._timer_expired(self._off_route_started_at, REROUTE_TRIGGER_SECONDS, now) + should_reroute |= self._timer_expired(self._bearing_misaligned_started_at, REROUTE_TRIGGER_SECONDS, now) + if should_reroute: + self._start_route_fetch(destination) + + if self._timer_expired(self._arrival_started_at, ARRIVAL_CLEAR_SECONDS, now): + self._clear_route(remove_destination=True) + + def _publish_nav_instruction(self, route: NavigationRoute | None, progress: RouteProgress | None, location_valid: bool) -> None: + msg = messaging.new_message("navInstruction") + msg.valid = bool(route is not None and progress is not None and location_valid) + + if msg.valid and route is not None and progress is not None and self._last_position is not None: + payload = route.build_instruction_payload( + progress, + use_vienna_sign=self.params.get_bool("UseVienna"), + ) + nav_instruction = msg.navInstruction + nav_instruction.maneuverPrimaryText = payload["maneuverPrimaryText"] + nav_instruction.maneuverSecondaryText = payload["maneuverSecondaryText"] + nav_instruction.maneuverDistance = float(payload["maneuverDistance"]) + nav_instruction.maneuverType = str(payload["maneuverType"]) + nav_instruction.maneuverModifier = str(payload["maneuverModifier"]) + nav_instruction.distanceRemaining = float(payload["distanceRemaining"]) + nav_instruction.timeRemaining = float(payload["timeRemaining"]) + nav_instruction.timeRemainingTypical = float(payload["timeRemainingTypical"]) + nav_instruction.lanes = payload["lanes"] + nav_instruction.showFull = bool(payload["showFull"]) + nav_instruction.speedLimit = float(payload["speedLimit"]) + nav_instruction.speedLimitSign = payload["speedLimitSign"] + nav_instruction.allManeuvers = payload["allManeuvers"] + + self.pm.send("navInstruction", msg) + + def _publish_nav_state(self, route: NavigationRoute | None, progress: RouteProgress | None, location_valid: bool) -> None: + if route is None or progress is None or not location_valid: + if self._last_nav_state is not None: + self.params_memory.remove("NavInstructionState") + self._last_nav_state = None + return + + modifier = progress.current_step.modifier or "" + if progress.current_step.banner_instructions: + try: + payload = route.build_instruction_payload(progress, use_vienna_sign=self.params.get_bool("UseVienna")) + modifier = str(payload.get("maneuverModifier") or modifier) + except Exception: + pass + + state = { + "valid": True, + "maneuverModifier": modifier, + } + if state != self._last_nav_state: + self.params_memory.put_nonblocking("NavInstructionState", state) + self._last_nav_state = state + + def _publish_nav_route_if_needed(self) -> None: + route, _, route_generation = self._snapshot_route() + if route_generation == self._published_route_generation: + return + + msg = messaging.new_message("navRoute") + msg.valid = route is not None + if route is not None: + msg.navRoute.coordinates = [ + {"latitude": coordinate.latitude, "longitude": coordinate.longitude} + for coordinate in route.geometry + ] + + self.pm.send("navRoute", msg) + self._published_route_generation = route_generation + + def run(self) -> None: + cloudlog.warning("navigationd init") + + while True: + self.sm.update(0) + + location_valid = self._update_location() + current_destination = parse_destination_json(self.params.get("NavDestination", encoding="utf-8")) + route, active_destination, _ = self._maybe_update_route(current_destination) + + v_ego = float(max(self.sm["carState"].vEgo, 0.0)) + progress, route_state = self._build_progress(route, location_valid, v_ego) + self._maybe_recompute(route, current_destination or active_destination, progress, route_state) + updated_route, active_destination, _ = self._snapshot_route() + if updated_route is not route and updated_route is not None and location_valid and self._last_position is not None: + progress = updated_route.get_progress(self._last_position) + route = updated_route + if route is None: + progress = None + + self._publish_nav_instruction(route, progress, location_valid) + self._publish_nav_state(route, progress, location_valid) + self._publish_nav_route_if_needed() + self.rk.keep_time() + + +def main() -> None: + Navigationd().run() + + +if __name__ == "__main__": + main() diff --git a/starpilot/navigation/route_engine.py b/starpilot/navigation/route_engine.py new file mode 100644 index 000000000..71e905414 --- /dev/null +++ b/starpilot/navigation/route_engine.py @@ -0,0 +1,434 @@ +from __future__ import annotations + +import math +from dataclasses import dataclass +from typing import Any + +import numpy as np +import requests + +from cereal import log +from openpilot.common.constants import CV + +DIRECTIONS = ("left", "right", "straight") +MODIFIABLE_DIRECTIONS = ("left", "right") + +EARTH_MEAN_RADIUS = 6371007.2 +SPEED_CONVERSIONS = { + "km/h": CV.KPH_TO_MS, + "mph": CV.MPH_TO_MS, +} + +OFF_ROUTE_SPEED_BREAKPOINTS = [0.0, 5.0, 10.0, 20.0, 40.0] +OFF_ROUTE_DISTANCE_BREAKPOINTS = [100.0, 125.0, 150.0, 200.0, 250.0] +UPCOMING_TURN_SPEED_BREAKPOINTS = [0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35.0, 40.0] +UPCOMING_TURN_DISTANCE_BREAKPOINTS = [20.0, 25.0, 30.0, 45.0, 60.0, 75.0, 90.0, 105.0, 120.0] +UTURN_MODIFIER = "uturn" + +LANE_DIRECTIONS = frozenset({ + "none", + "left", + "right", + "straight", + "slightLeft", + "slightRight", +}) + + +@dataclass(frozen=True) +class Coordinate: + latitude: float + longitude: float + + def __sub__(self, other: "Coordinate") -> "Coordinate": + return Coordinate(self.latitude - other.latitude, self.longitude - other.longitude) + + def __add__(self, other: "Coordinate") -> "Coordinate": + return Coordinate(self.latitude + other.latitude, self.longitude + other.longitude) + + def __mul__(self, scale: float) -> "Coordinate": + return Coordinate(self.latitude * scale, self.longitude * scale) + + def dot(self, other: "Coordinate") -> float: + return self.latitude * other.latitude + self.longitude * other.longitude + + def distance_to(self, other: "Coordinate") -> float: + dlat = math.radians(other.latitude - self.latitude) + dlon = math.radians(other.longitude - self.longitude) + + haversine_dlat = math.sin(dlat / 2.0) ** 2 + haversine_dlon = math.sin(dlon / 2.0) ** 2 + + a = haversine_dlat + math.cos(math.radians(self.latitude)) * math.cos(math.radians(other.latitude)) * haversine_dlon + return 2.0 * math.asin(math.sqrt(a)) * EARTH_MEAN_RADIUS + + +@dataclass(frozen=True) +class RouteStep: + banner_instructions: list[dict[str, Any]] + distance: float + duration: float + maneuver: str + location: Coordinate + cumulative_distance: float + maxspeed_ms: float + modifier: str + instruction: str + + +@dataclass(frozen=True) +class RouteProgress: + closest_index: int + distance_from_route: float + current_step: RouteStep + next_step: RouteStep | None + current_step_index: int + distance_to_end_of_step: float + distance_remaining: float + time_remaining: float + current_speed_limit_ms: float + all_maneuvers: list[dict[str, Any]] + + +def bearing_between_two_points(point_one: Coordinate, point_two: Coordinate) -> float: + lat_one = math.radians(point_one.latitude) + lat_two = math.radians(point_two.latitude) + dlon = math.radians(point_two.longitude - point_one.longitude) + + bearing_radians = math.atan2( + math.sin(dlon) * math.cos(lat_two), + math.cos(lat_one) * math.sin(lat_two) - math.sin(lat_one) * math.cos(lat_two) * math.cos(dlon), + ) + return (math.degrees(bearing_radians) + 360.0) % 360.0 + + +def minimum_distance(a: Coordinate, b: Coordinate, p: Coordinate) -> float: + if a.distance_to(b) < 0.01: + return a.distance_to(p) + + ap = p - a + ab = b - a + t = np.clip(ap.dot(ab) / ab.dot(ab), 0.0, 1.0) + projection = a + ab * t + return projection.distance_to(p) + + +def distance_along_geometry(geometry: list[Coordinate], position: Coordinate) -> float: + if len(geometry) <= 2: + return geometry[0].distance_to(position) + + total_distance = 0.0 + closest_total_distance = 0.0 + closest_distance = 1e9 + + for index in range(len(geometry) - 1): + segment_distance = minimum_distance(geometry[index], geometry[index + 1], position) + if segment_distance < closest_distance: + closest_distance = segment_distance + closest_total_distance = total_distance + geometry[index].distance_to(position) + total_distance += geometry[index].distance_to(geometry[index + 1]) + + return closest_total_distance + + +def string_to_direction(direction: str) -> str: + normalized = direction or "" + for direction_name in DIRECTIONS: + if direction_name not in normalized: + continue + if "slight" in normalized and direction_name in MODIFIABLE_DIRECTIONS: + return f"slight{direction_name.capitalize()}" + if "sharp" in normalized and direction_name in MODIFIABLE_DIRECTIONS: + return f"sharp{direction_name.capitalize()}" + return direction_name + + if "uturn" in normalized or "u-turn" in normalized: + return UTURN_MODIFIER + + return "none" + + +def normalize_lane_direction(direction: str) -> str: + normalized = string_to_direction(direction) + return normalized if normalized in LANE_DIRECTIONS else "none" + + +def maxspeed_to_ms(maxspeed: dict[str, str | float]) -> float: + unit = str(maxspeed["unit"]) + speed = float(maxspeed["speed"]) + return float(SPEED_CONVERSIONS[unit] * speed) + + +def field_valid(dat: dict[str, Any], field: str) -> bool: + return field in dat and dat[field] is not None + + +def parse_banner_instructions(banners: Any, distance_to_maneuver: float = 0.0) -> dict[str, Any] | None: + if not banners: + return None + + instruction: dict[str, Any] = {} + current_banner = banners[0] + for banner in banners: + if distance_to_maneuver < banner["distanceAlongGeometry"]: + current_banner = banner + + instruction["showFull"] = distance_to_maneuver < current_banner["distanceAlongGeometry"] + + primary = current_banner["primary"] + if field_valid(primary, "text"): + instruction["maneuverPrimaryText"] = primary["text"] + if field_valid(primary, "type"): + instruction["maneuverType"] = primary["type"] + if field_valid(primary, "modifier"): + instruction["maneuverModifier"] = string_to_direction(primary["modifier"]) + + if field_valid(current_banner, "secondary"): + instruction["maneuverSecondaryText"] = current_banner["secondary"]["text"] + + if field_valid(current_banner, "sub"): + lanes = [] + for component in current_banner["sub"]["components"]: + if component["type"] != "lane": + continue + + lane = { + "active": component["active"], + "directions": [normalize_lane_direction(direction) for direction in component["directions"]], + } + if field_valid(component, "active_direction"): + lane["activeDirection"] = normalize_lane_direction(component["active_direction"]) + lanes.append(lane) + instruction["lanes"] = lanes + + return instruction + + +@dataclass +class NavigationRoute: + geometry: list[Coordinate] + bearings: list[float] + steps: list[RouteStep] + total_distance: float + total_duration: float + + @classmethod + def from_mapbox_route(cls, route_data: dict[str, Any]) -> "NavigationRoute" | None: + geometry_data = route_data.get("geometry") or [] + steps_data = route_data.get("steps") or [] + if not geometry_data or not steps_data: + return None + + geometry = [Coordinate(float(coord["latitude"]), float(coord["longitude"])) for coord in geometry_data] + cumulative_distances = [0.0] + for index in range(1, len(geometry)): + cumulative_distances.append(cumulative_distances[-1] + geometry[index - 1].distance_to(geometry[index])) + + maxspeeds = [maxspeed_to_ms(item) for item in route_data.get("maxspeed", []) if field_valid(item, "speed") and field_valid(item, "unit")] + + steps: list[RouteStep] = [] + for step in steps_data: + location = Coordinate(float(step["location"]["latitude"]), float(step["location"]["longitude"])) + closest_index = min(range(len(geometry)), key=lambda idx: location.distance_to(geometry[idx])) + maxspeed_ms = maxspeeds[min(closest_index, len(maxspeeds) - 1)] if maxspeeds else 0.0 + steps.append(RouteStep( + banner_instructions=step.get("bannerInstructions", []), + distance=float(step["distance"]), + duration=float(step["duration"]), + maneuver=str(step["maneuver"]), + location=location, + cumulative_distance=cumulative_distances[closest_index], + maxspeed_ms=maxspeed_ms, + modifier=string_to_direction(str(step.get("modifier", "none"))), + instruction=str(step.get("instruction", "")), + )) + + bearings = [bearing_between_two_points(geometry[index], geometry[index + 2]) for index in range(len(geometry) - 2)] + return cls( + geometry=geometry, + bearings=bearings, + steps=steps, + total_distance=float(route_data.get("totalDistance", 0.0)), + total_duration=float(route_data.get("totalDuration", 0.0)), + ) + + def route_bearing_misaligned(self, closest_index: int, current_bearing: float | None, v_ego: float) -> bool: + if current_bearing is None or v_ego < 5.0 or closest_index <= 0 or closest_index >= len(self.geometry) - 1: + return False + if closest_index - 1 >= len(self.bearings): + return False + + route_bearing = self.bearings[closest_index - 1] + normalized_bearing = (current_bearing + 360.0) % 360.0 + bearing_difference = abs(normalized_bearing - route_bearing) + return min(bearing_difference, 360.0 - bearing_difference) > 110.0 + + def get_progress(self, position: Coordinate) -> RouteProgress | None: + if not self.geometry or not self.steps: + return None + + closest_index, min_distance = min( + ((idx, position.distance_to(coord)) for idx, coord in enumerate(self.geometry)), + key=lambda item: item[1], + ) + closest_cumulative = distance_along_geometry(self.geometry, position) + + current_step_index = max( + (idx for idx, step in enumerate(self.steps) if step.cumulative_distance <= closest_cumulative), + default=-1, + ) + current_step = self.steps[current_step_index if current_step_index >= 0 else 0] + next_step_index = current_step_index + 1 + next_step = self.steps[next_step_index] if 0 <= next_step_index < len(self.steps) else None + + distance_to_end_of_step = max(0.0, current_step.distance - (closest_cumulative - current_step.cumulative_distance)) + distance_remaining = max(0.0, self.total_distance - closest_cumulative) + + current_step_distance = max(current_step.distance, 1.0) + remaining_current_duration = current_step.duration * min(distance_to_end_of_step / current_step_distance, 1.0) + later_duration = sum(step.duration for step in self.steps[next_step_index:]) + time_remaining = max(0.0, remaining_current_duration + later_duration) + + all_maneuvers: list[dict[str, Any]] = [] + start_index = max(current_step_index, 0) + end_index = min(start_index + 3, len(self.steps)) + for index in range(start_index, end_index): + step = self.steps[index] + maneuver_distance = distance_to_end_of_step if index == start_index else max(0.0, step.cumulative_distance - closest_cumulative) + all_maneuvers.append({ + "distance": maneuver_distance, + "type": step.maneuver, + "modifier": step.modifier, + }) + + return RouteProgress( + closest_index=closest_index, + distance_from_route=min_distance, + current_step=current_step, + next_step=next_step, + current_step_index=max(current_step_index, 0), + distance_to_end_of_step=distance_to_end_of_step, + distance_remaining=distance_remaining, + time_remaining=time_remaining, + current_speed_limit_ms=current_step.maxspeed_ms, + all_maneuvers=all_maneuvers, + ) + + def upcoming_turn_modifier(self, progress: RouteProgress, position: Coordinate, v_ego: float) -> str: + if progress.next_step is None: + return "none" + + distance_threshold = float(np.interp(v_ego, UPCOMING_TURN_SPEED_BREAKPOINTS, UPCOMING_TURN_DISTANCE_BREAKPOINTS)) + if position.distance_to(progress.next_step.location) <= distance_threshold: + return progress.next_step.modifier + return "none" + + def off_route_distance_exceeded(self, progress: RouteProgress, v_ego: float) -> bool: + distance_threshold = float(np.interp(v_ego, OFF_ROUTE_SPEED_BREAKPOINTS, OFF_ROUTE_DISTANCE_BREAKPOINTS)) + return progress.distance_from_route > distance_threshold + + def arrived(self, progress: RouteProgress, v_ego: float) -> bool: + if v_ego >= 1.0 or not progress.all_maneuvers: + return False + current = progress.all_maneuvers[0] + return current["type"] == "arrive" or progress.current_step.instruction.startswith("Your destination") + + def build_instruction_payload(self, progress: RouteProgress, *, use_vienna_sign: bool = False) -> dict[str, Any]: + parsed = parse_banner_instructions(progress.current_step.banner_instructions, progress.distance_to_end_of_step) or {} + primary_text = parsed.get("maneuverPrimaryText") or progress.current_step.instruction + secondary_text = parsed.get("maneuverSecondaryText") or "" + maneuver_type = parsed.get("maneuverType") or progress.current_step.maneuver + maneuver_modifier = parsed.get("maneuverModifier") or progress.current_step.modifier + lanes = [] + for lane in parsed.get("lanes", []): + directions = [direction for direction in lane.get("directions", []) if direction in LANE_DIRECTIONS] + active_direction = lane.get("activeDirection", "none") + lanes.append({ + "directions": directions or ["none"], + "active": bool(lane.get("active", False)), + "activeDirection": active_direction if active_direction in LANE_DIRECTIONS else "none", + }) + + return { + "maneuverPrimaryText": primary_text, + "maneuverSecondaryText": secondary_text, + "maneuverDistance": progress.distance_to_end_of_step, + "maneuverType": maneuver_type, + "maneuverModifier": maneuver_modifier, + "distanceRemaining": progress.distance_remaining, + "timeRemaining": progress.time_remaining, + "timeRemainingTypical": progress.time_remaining, + "lanes": lanes, + "showFull": bool(parsed.get("showFull", True)), + "speedLimit": progress.current_speed_limit_ms, + "speedLimitSign": log.NavInstruction.SpeedLimitSign.vienna if use_vienna_sign else log.NavInstruction.SpeedLimitSign.mutcd, + "allManeuvers": progress.all_maneuvers, + } + + +class MapboxRouteEngine: + DIRECTIONS_URL = "https://api.mapbox.com/directions/v5/mapbox/driving" + + def __init__(self, session: Any = requests): + self._session = session + + def fetch_route(self, token: str, start: Coordinate, destination: dict[str, Any], bearing: float | None = None) -> NavigationRoute | None: + if not token: + return None + + end = Coordinate(float(destination["latitude"]), float(destination["longitude"])) + params: dict[str, str] = { + "access_token": token, + "geometries": "geojson", + "steps": "true", + "overview": "full", + "annotations": "maxspeed", + "alternatives": "false", + "banner_instructions": "true", + } + if bearing is not None: + params["bearings"] = f"{int((bearing + 360.0) % 360.0)},90;" + + url = f"{self.DIRECTIONS_URL}/{start.longitude},{start.latitude};{end.longitude},{end.latitude}" + try: + response = self._session.get(url, params=params, timeout=5) + data = response.json() if response.status_code == 200 else {} + except requests.RequestException: + return None + + routes = data.get("routes") or [] + route = routes[0] if routes else None + legs = route.get("legs") if route else None + leg = legs[0] if legs else None + if data.get("code") != "Ok" or route is None or leg is None: + return None + + route_data = { + "steps": [ + { + "maneuver": step["maneuver"]["type"], + "instruction": step["maneuver"]["instruction"], + "distance": step["distance"], + "duration": step["duration"], + "location": { + "longitude": step["maneuver"]["location"][0], + "latitude": step["maneuver"]["location"][1], + }, + "modifier": step["maneuver"].get("modifier", "none"), + "bannerInstructions": step.get("bannerInstructions", []), + } + for step in leg.get("steps", []) + ], + "totalDistance": route["distance"], + "totalDuration": route["duration"], + "geometry": [ + {"longitude": coord[0], "latitude": coord[1]} + for coord in route["geometry"]["coordinates"] + ], + "maxspeed": [ + {"speed": item["speed"], "unit": item["unit"]} + for item in leg.get("annotation", {}).get("maxspeed", []) + if field_valid(item, "speed") and field_valid(item, "unit") + ], + } + return NavigationRoute.from_mapbox_route(route_data) diff --git a/starpilot/navigation/test_destination_store.py b/starpilot/navigation/test_destination_store.py new file mode 100644 index 000000000..cab470df7 --- /dev/null +++ b/starpilot/navigation/test_destination_store.py @@ -0,0 +1,48 @@ +import json + +from openpilot.starpilot.navigation.destination_store import ( + normalize_destination_payload, + update_recent_destinations, +) + + +def test_normalize_destination_payload_requires_name_and_coordinates(): + payload = { + "name": "123 Main St", + "latitude": "41.881832", + "longitude": "-87.623177", + } + + assert normalize_destination_payload(payload) == { + "name": "123 Main St", + "place_name": "123 Main St", + "latitude": 41.881832, + "longitude": -87.623177, + } + assert normalize_destination_payload({"name": "Missing coords"}) is None + + +def test_recent_destinations_dedupe_and_cap(): + existing = json.dumps([ + {"place_name": "Old 1"}, + {"place_name": "Old 2"}, + {"place_name": "Home"}, + {"place_name": "Old 3"}, + {"place_name": "Old 4"}, + {"place_name": "Old 5"}, + {"place_name": "Old 6"}, + {"place_name": "Old 7"}, + {"place_name": "Old 8"}, + {"place_name": "Old 9"}, + ]) + + updated = update_recent_destinations(existing, { + "name": "Home", + "latitude": 1.0, + "longitude": 2.0, + }) + + assert updated[0]["place_name"] == "Home" + assert len(updated) == 10 + assert [entry["place_name"] for entry in updated].count("Home") == 1 + assert updated[-1]["place_name"] == "Old 9" diff --git a/starpilot/navigation/test_route_engine.py b/starpilot/navigation/test_route_engine.py new file mode 100644 index 000000000..bb6b7133f --- /dev/null +++ b/starpilot/navigation/test_route_engine.py @@ -0,0 +1,153 @@ +from cereal import log + +from openpilot.starpilot.navigation.route_engine import Coordinate, NavigationRoute + + +def make_route() -> NavigationRoute: + route_data = { + "geometry": [ + {"latitude": 0.0, "longitude": 0.0}, + {"latitude": 0.0, "longitude": 0.001}, + {"latitude": 0.0, "longitude": 0.002}, + {"latitude": 0.001, "longitude": 0.002}, + ], + "steps": [ + { + "maneuver": "depart", + "instruction": "Head east", + "distance": 220.0, + "duration": 20.0, + "location": {"latitude": 0.0, "longitude": 0.0}, + "modifier": "straight", + "bannerInstructions": [ + { + "distanceAlongGeometry": 80.0, + "primary": { + "text": "Turn right", + "type": "turn", + "modifier": "right", + }, + "secondary": {"text": "onto Market St"}, + }, + ], + }, + { + "maneuver": "turn", + "instruction": "Turn right onto Market St", + "distance": 111.0, + "duration": 10.0, + "location": {"latitude": 0.0, "longitude": 0.002}, + "modifier": "right", + "bannerInstructions": [], + }, + { + "maneuver": "arrive", + "instruction": "Your destination is on the right", + "distance": 0.0, + "duration": 0.0, + "location": {"latitude": 0.001, "longitude": 0.002}, + "modifier": "right", + "bannerInstructions": [], + }, + ], + "totalDistance": 331.0, + "totalDuration": 30.0, + "maxspeed": [ + {"speed": 35.0, "unit": "mph"}, + {"speed": 35.0, "unit": "mph"}, + {"speed": 25.0, "unit": "mph"}, + {"speed": 25.0, "unit": "mph"}, + ], + } + route = NavigationRoute.from_mapbox_route(route_data) + assert route is not None + return route + + +def test_route_progress_and_instruction_payload(): + route = make_route() + progress = route.get_progress(Coordinate(0.0, 0.0015)) + + assert progress is not None + assert progress.current_step_index == 0 + assert progress.distance_remaining > 0 + assert route.upcoming_turn_modifier(progress, Coordinate(0.0, 0.0015), 20.0) == "right" + + payload = route.build_instruction_payload(progress) + assert payload["maneuverPrimaryText"] == "Turn right" + assert payload["maneuverSecondaryText"] == "onto Market St" + assert payload["maneuverType"] == "turn" + assert payload["maneuverModifier"] == "right" + + +def test_route_off_route_and_arrival_detection(): + route = make_route() + off_route_progress = route.get_progress(Coordinate(0.0020, 0.0010)) + misaligned_progress = route.get_progress(Coordinate(0.0, 0.0015)) + arrive_progress = route.get_progress(Coordinate(0.0010, 0.0020)) + + assert off_route_progress is not None + assert misaligned_progress is not None + assert arrive_progress is not None + assert route.off_route_distance_exceeded(off_route_progress, 10.0) + assert route.route_bearing_misaligned(misaligned_progress.closest_index, 270.0, 10.0) + assert route.arrived(arrive_progress, 0.5) + + +def test_lane_payload_uses_capnp_enum_names(): + route_data = { + "geometry": [ + {"latitude": 0.0, "longitude": 0.0}, + {"latitude": 0.0, "longitude": 0.001}, + {"latitude": 0.0, "longitude": 0.002}, + ], + "steps": [ + { + "maneuver": "turn", + "instruction": "Keep left", + "distance": 120.0, + "duration": 12.0, + "location": {"latitude": 0.0, "longitude": 0.001}, + "modifier": "slight left", + "bannerInstructions": [ + { + "distanceAlongGeometry": 80.0, + "primary": { + "text": "Keep left", + "type": "turn", + "modifier": "slight left", + }, + "sub": { + "components": [ + { + "type": "lane", + "active": True, + "directions": ["straight", "slight left"], + "active_direction": "slight left", + }, + ], + }, + }, + ], + }, + ], + "totalDistance": 120.0, + "totalDuration": 12.0, + } + + route = NavigationRoute.from_mapbox_route(route_data) + assert route is not None + progress = route.get_progress(Coordinate(0.0, 0.0005)) + assert progress is not None + + payload = route.build_instruction_payload(progress) + msg = log.Event.new_message() + msg.init("navInstruction") + msg.navInstruction.lanes = payload["lanes"] + + assert len(msg.navInstruction.lanes) == 1 + assert list(msg.navInstruction.lanes[0].directions) == [ + log.NavInstruction.Direction.straight, + log.NavInstruction.Direction.slightLeft, + ] + assert msg.navInstruction.lanes[0].activeDirection == log.NavInstruction.Direction.slightLeft diff --git a/starpilot/system/the_pond/assets/components/sidebar.js b/starpilot/system/the_pond/assets/components/sidebar.js index ed5a71b03..968a79356 100644 --- a/starpilot/system/the_pond/assets/components/sidebar.js +++ b/starpilot/system/the_pond/assets/components/sidebar.js @@ -17,6 +17,7 @@ const MENU_ITEMS = { { name: "Lateral Maneuvers", link: "/lateral_maneuvers", icon: "bi-sign-turn-right" }, { name: "Long Maneuvers", link: "/longitudinal_maneuvers", icon: "bi-signpost-split" }, { name: "Maps", link: "/manage_maps", icon: "bi-map" }, + { name: "Navigation", link: "/set_navigation_destination", icon: "bi-geo-alt-fill" }, { name: "Navigation Keys", link: "/manage_navigation_keys", icon: "bi-key-fill" }, { name: "Model Manager", link: "/manage_models", icon: "bi-cpu" }, { name: "Plots", link: "/plots", icon: "bi-graph-up-arrow" }, diff --git a/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json b/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json index c9c126426..37935567f 100644 --- a/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json +++ b/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json @@ -200,6 +200,14 @@ "ui_type": "toggle", "parent_key": "LateralTune" }, + { + "key": "NavDesiresAllowed", + "label": "Use Route Desires", + "description": "Allow an active navigation route to request keep-left, keep-right, and low-speed turn desires.", + "data_type": "bool", + "ui_type": "toggle", + "parent_key": "LateralTune" + }, { "key": "NNFF", "label": "Neural Network Feedforward (NNFF)", diff --git a/starpilot/system/the_pond/the_pond.py b/starpilot/system/the_pond/the_pond.py index cd2cbd2ff..bd0ad356e 100644 --- a/starpilot/system/the_pond/the_pond.py +++ b/starpilot/system/the_pond/the_pond.py @@ -77,6 +77,7 @@ from openpilot.starpilot.common.testing_grounds import ( TESTING_GROUNDS_SLOT_DEFINITIONS as SHARED_TESTING_GROUNDS_SLOT_DEFINITIONS, TESTING_GROUNDS_STATE_PATH as SHARED_TESTING_GROUNDS_STATE_PATH, ) +from openpilot.starpilot.navigation.destination_store import normalize_destination_payload, update_recent_destinations from openpilot.starpilot.system.the_pond import utilities DISCORD_WEBHOOK_URL = os.getenv("DISCORD_WEBHOOK_URL") @@ -3464,11 +3465,16 @@ def setup(app): @app.route("/api/navigation", methods=["POST"]) def set_navigation(): - params.remove("NavDestination") + destination = normalize_destination_payload(request.json) + if destination is None: + return {"message": "Invalid destination payload"}, 400 - time.sleep(1) - - params.put("NavDestination", json.dumps(request.json)) + recent_destinations = update_recent_destinations( + params.get("ApiCache_NavDestinations", encoding="utf8") or "", + destination, + ) + params.put("NavDestination", json.dumps(destination)) + params.put("ApiCache_NavDestinations", json.dumps(recent_destinations)) return {"message": "Destination set"} @app.route("/api/navigation/favorite", methods=["DELETE"]) diff --git a/starpilot/ui/qt/offroad/lateral_settings.cc b/starpilot/ui/qt/offroad/lateral_settings.cc index 10dbd392a..a5d5d9791 100644 --- a/starpilot/ui/qt/offroad/lateral_settings.cc +++ b/starpilot/ui/qt/offroad/lateral_settings.cc @@ -55,6 +55,7 @@ StarPilotLateralPanel::StarPilotLateralPanel(StarPilotSettingsWindow *parent, bo {"LateralTune", tr("Lateral Tuning"), tr("Miscellaneous steering control changes to fine-tune how openpilot drives."), "../../starpilot/assets/toggle_icons/icon_lateral_tune.png"}, {"TurnDesires", tr("Force Turn Desires Below Lane Change Speed"), tr("While driving below the minimum lane change speed with an active turn signal, instruct openpilot to turn left/right."), ""}, + {"NavDesiresAllowed", tr("Use Route Desires"), tr("Allow an active navigation route to request keep-left, keep-right, and low-speed turn desires."), ""}, {"NNFF", tr("Neural Network Feedforward (NNFF)"), tr("Twilsonco's \"Neural Network FeedForward\" controller. Uses a trained neural network model to predict steering torque based on vehicle speed, roll, and past/future planned path data for smoother, model-based steering."), ""}, {"NNFFLite", tr("Neural Network Feedforward (NNFF) Lite"), tr("A lightweight version of Twilsonco's \"Neural Network FeedForward\" controller. Uses the \"look-ahead\" planned lateral jerk logic from the full model to help smoothen steering adjustments in curves, but does not use the full neural network for torque calculation."), ""}, diff --git a/starpilot/ui/qt/offroad/lateral_settings.h b/starpilot/ui/qt/offroad/lateral_settings.h index a8eac5635..5bf83e39c 100644 --- a/starpilot/ui/qt/offroad/lateral_settings.h +++ b/starpilot/ui/qt/offroad/lateral_settings.h @@ -27,7 +27,7 @@ private: QSet advancedLateralTuneKeys = {"ForceAutoTune", "ForceAutoTuneOff", "ForceTorqueController", "SteerDelay", "SteerFriction", "SteerLatAccel", "SteerKP", "SteerRatio"}; QSet aolKeys = {"AlwaysOnLateralLKAS", "PauseAOLOnBrake"}; QSet laneChangeKeys = {"LaneChangeSmoothing", "LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"}; - QSet lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"}; + QSet lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires", "NavDesiresAllowed"}; QSet qolKeys = {"PauseLateralSpeed", "LateralResumeDelay"}; QSet parentKeys; diff --git a/system/manager/process_config.py b/system/manager/process_config.py index abfd71546..420a90823 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -80,6 +80,9 @@ def run_speed_limit_filler(started: bool, params: Params, CP: car.CarParams, sta def run_speed_limit_vision(started: bool, params: Params, CP: car.CarParams, starpilot_toggles: SimpleNamespace) -> bool: return starpilot_toggles.vision_speed_limit_detection +def run_navigationd(started: bool, params: Params, CP: car.CarParams, starpilot_toggles: SimpleNamespace) -> bool: + return started and params.get("NavDestination") is not None + procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), @@ -150,7 +153,8 @@ else: procs += [ PythonProcess("device_syncd", "starpilot.system.device_syncd", always_run), PythonProcess("starpilot_process", "starpilot.starpilot_process", always_run), - PythonProcess("mapd", "starpilot.navigation.mapd_wrapper", always_run), + PythonProcess("mapd", "starpilot.navigation.mapd_wrapper", always_run, nice=19), + PythonProcess("navigationd", "starpilot.navigation.navigationd", run_navigationd, nice=19), PythonProcess("speed_limit_filler", "starpilot.system.speed_limit_filler", run_speed_limit_filler, nice=19), PythonProcess("speed_limit_vision", "starpilot.system.speed_limit_vision", run_speed_limit_vision, nice=19), ] diff --git a/tools/replay/fake_nav_demo.py b/tools/replay/fake_nav_demo.py new file mode 100644 index 000000000..9424577f3 --- /dev/null +++ b/tools/replay/fake_nav_demo.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 + +import argparse +import time +from itertools import cycle + +from cereal import log, messaging + + +ROUTE_COORDS = [ + {"latitude": 0.0, "longitude": 0.0}, + {"latitude": 0.0, "longitude": 0.01}, + {"latitude": 0.01, "longitude": 0.02}, +] + + +SCENARIOS = [ + { + "primary": "Turn right onto Main St", + "secondary": "Then keep left", + "distance": 120.0, + "type": "turn", + "modifier": "right", + "next_type": "fork", + "next_modifier": "slightLeft", + }, + { + "primary": "Turn left onto Pine Ave", + "secondary": "Then merge right", + "distance": 180.0, + "type": "turn", + "modifier": "left", + "next_type": "merge", + "next_modifier": "right", + }, + { + "primary": "Keep right to stay on I-90", + "secondary": "Then continue straight", + "distance": 260.0, + "type": "fork", + "modifier": "slightRight", + "next_type": "continue", + "next_modifier": "straight", + }, + { + "primary": "Keep left to stay on I-90", + "secondary": "Then take exit 14A", + "distance": 210.0, + "type": "fork", + "modifier": "slightLeft", + "next_type": "off ramp", + "next_modifier": "right", + }, + { + "primary": "Take exit 14A", + "secondary": "Then turn sharp right", + "distance": 340.0, + "type": "off ramp", + "modifier": "right", + "next_type": "turn", + "next_modifier": "sharpRight", + }, + { + "primary": "Continue straight for 1 mile", + "secondary": "Then enter the roundabout", + "distance": 1600.0, + "type": "continue", + "modifier": "straight", + "next_type": "roundabout", + "next_modifier": "right", + }, + { + "primary": "Enter the roundabout", + "secondary": "Take the second exit", + "distance": 90.0, + "type": "roundabout", + "modifier": "right", + "next_type": "turn", + "next_modifier": "left", + }, + { + "primary": "Turn sharp left onto Oak St", + "secondary": "Then make a U-turn", + "distance": 75.0, + "type": "turn", + "modifier": "sharpLeft", + "next_type": "continue", + "next_modifier": "uturn", + }, + { + "primary": "Make a U-turn", + "secondary": "Then arrive at destination", + "distance": 60.0, + "type": "continue", + "modifier": "uturn", + "next_type": "arrive", + "next_modifier": "right", + }, + { + "primary": "Arrive at destination", + "secondary": "Destination is on the right", + "distance": 25.0, + "type": "arrive", + "modifier": "right", + "next_type": "turn", + "next_modifier": "straight", + }, +] + + +def build_instruction(pm: messaging.PubMaster, scenario: dict) -> None: + msg = messaging.new_message("navInstruction") + msg.valid = True + + nav = msg.navInstruction + nav.maneuverPrimaryText = scenario["primary"] + nav.maneuverSecondaryText = scenario["secondary"] + nav.maneuverDistance = scenario["distance"] + nav.maneuverType = scenario["type"] + nav.maneuverModifier = scenario["modifier"] + nav.distanceRemaining = max(scenario["distance"] * 8, 400.0) + nav.timeRemaining = max(scenario["distance"] / 10.0, 20.0) + nav.timeRemainingTypical = nav.timeRemaining + nav.showFull = True + nav.speedLimit = 31.2928 + nav.speedLimitSign = log.NavInstruction.SpeedLimitSign.mutcd + nav.allManeuvers = [ + {"distance": scenario["distance"], "type": scenario["type"], "modifier": scenario["modifier"]}, + {"distance": scenario["distance"] + 220.0, "type": scenario["next_type"], "modifier": scenario["next_modifier"]}, + ] + + pm.send("navInstruction", msg) + + +def build_route(pm: messaging.PubMaster) -> None: + msg = messaging.new_message("navRoute") + msg.valid = True + msg.navRoute.coordinates = ROUTE_COORDS + pm.send("navRoute", msg) + + +def main() -> None: + parser = argparse.ArgumentParser(description="Publish fake navigation instructions for desktop onroad replay.") + parser.add_argument("--hold-seconds", type=float, default=3.0, help="How long each maneuver stays active.") + parser.add_argument("--publish-interval", type=float, default=0.25, help="Seconds between navInstruction publishes.") + args = parser.parse_args() + + pm = messaging.PubMaster(["navInstruction", "navRoute"]) + + scenario_cycle = cycle(SCENARIOS) + current = next(scenario_cycle) + next_switch = time.monotonic() + args.hold_seconds + print(f"showing: {current['type']} / {current['modifier']} -> {current['next_type']} / {current['next_modifier']}", flush=True) + + while True: + now = time.monotonic() + if now >= next_switch: + current = next(scenario_cycle) + next_switch = now + args.hold_seconds + print(f"showing: {current['type']} / {current['modifier']} -> {current['next_type']} / {current['next_modifier']}", flush=True) + + build_instruction(pm, current) + build_route(pm) + time.sleep(args.publish_interval) + + +if __name__ == "__main__": + main()