Update mapd to v2

This commit is contained in:
James
2026-01-06 17:12:51 -07:00
parent 5e224f8c9a
commit d358250853
17 changed files with 281 additions and 322 deletions
+117 -3
View File
@@ -254,11 +254,125 @@ struct CustomReserved15 @0xbd443b539493bc68 {
struct CustomReserved16 @0xfc6241ed8877b611 {
}
struct CustomReserved17 @0xa30662f84033036c {
struct MapdDownloadLocationDetails @0xff889853e7b0987f {
location @0 :Text;
totalFiles @1 :UInt32;
downloadedFiles @2 :UInt32;
}
struct CustomReserved18 @0xc86a3d38d13eb3ef {
struct MapdDownloadProgress @0xfaa35dcac85073a2 {
active @0 :Bool;
cancelled @1 :Bool;
totalFiles @2 :UInt32;
downloadedFiles @3 :UInt32;
locations @4 :List(Text);
locationDetails @5 :List(MapdDownloadLocationDetails);
}
struct CustomReserved19 @0xa4f1eb3323f5f582 {
struct MapdPathPoint @0xd6f78acca1bc3939 {
latitude @0 :Float64;
longitude @1 :Float64;
curvature @2 :Float32;
targetVelocity @3 :Float32;
}
struct MapdExtendedOut @0xa30662f84033036c {
downloadProgress @0 :MapdDownloadProgress;
settings @1 :Text;
path @2 :List(MapdPathPoint);
}
enum MapdInputType {
download @0;
setTargetLateralAccel @1;
setSpeedLimitOffset @2;
setSpeedLimitControl @3;
setMapCurveSpeedControl @4;
setVisionCurveSpeedControl @5;
setLogLevel @6;
setVisionCurveTargetLatA @7;
setVisionCurveMinTargetV @8;
reloadSettings @9;
saveSettings @10;
setEnableSpeed @11;
setVisionCurveUseEnableSpeed @12;
setMapCurveUseEnableSpeed @13;
setSpeedLimitUseEnableSpeed @14;
setHoldLastSeenSpeedLimit @15;
setTargetSpeedJerk @16;
setTargetSpeedAccel @17;
setTargetSpeedTimeOffset @18;
setDefaultLaneWidth @19;
setMapCurveTargetLatA @20;
loadDefaultSettings @21;
loadRecommendedSettings @22;
setSlowDownForNextSpeedLimit @23;
setSpeedUpForNextSpeedLimit @24;
setHoldSpeedLimitWhileChangingSetSpeed @25;
loadPersistentSettings @26;
cancelDownload @27;
setLogJson @28;
setLogSource @29;
setExternalSpeedLimitControl @30;
setExternalSpeedLimit @31;
setSpeedLimitPriority @32;
setSpeedLimitChangeRequiresAccept @33;
acceptSpeedLimit @34;
setPressGasToAcceptSpeedLimit @35;
setAdjustSetSpeedToAcceptSpeedLimit @36;
setAcceptSpeedLimitTimeout @37;
setPressGasToOverrideSpeedLimit @38;
}
enum WaySelectionType {
current @0;
predicted @1;
possible @2;
extended @3;
fail @4;
}
enum SpeedLimitOffsetType {
static @0;
percent @1;
}
struct MapdIn @0xc86a3d38d13eb3ef {
type @0 :MapdInputType;
float @1 :Float32;
str @2 :Text;
bool @3 :Bool;
}
enum RoadContext {
freeway @0;
city @1;
unknown @2;
}
struct MapdOut @0xa4f1eb3323f5f582 {
wayName @0 :Text;
wayRef @1 :Text;
roadName @2 :Text;
speedLimit @3 :Float32;
nextSpeedLimit @4 :Float32;
nextSpeedLimitDistance @5 :Float32;
hazard @6 :Text;
nextHazard @7 :Text;
nextHazardDistance @8 :Float32;
advisorySpeed @9 :Float32;
nextAdvisorySpeed @10 :Float32;
nextAdvisorySpeedDistance @11 :Float32;
oneWay @12 :Bool;
lanes @13 :UInt8;
tileLoaded @14 :Bool;
speedLimitSuggestedSpeed @15 :Float32;
suggestedSpeed @16 :Float32;
estimatedRoadWidth @17 :Float32;
roadContext @18 :RoadContext;
distanceFromWayCenter @19 :Float32;
visionCurveSpeed @20 :Float32;
mapCurveSpeed @21 :Float32;
waySelectionType @22 :WaySelectionType;
speedLimitAccepted @23 :Bool;
}
+3 -3
View File
@@ -2642,9 +2642,9 @@ struct Event {
customReserved14 @140 :Custom.CustomReserved14;
customReserved15 @141 :Custom.CustomReserved15;
customReserved16 @142 :Custom.CustomReserved16;
customReserved17 @143 :Custom.CustomReserved17;
customReserved18 @144 :Custom.CustomReserved18;
customReserved19 @145 :Custom.CustomReserved19;
mapdExtendedOut @143 :Custom.MapdExtendedOut;
mapdIn @144 :Custom.MapdIn;
mapdOut @145 :Custom.MapdOut;
# *********** legacy + deprecated ***********
model @9 :Legacy.ModelData; # TODO: rename modelV2 and mark this as deprecated
+3
View File
@@ -113,6 +113,9 @@ _services: dict[str, tuple] = {
"frogpilotPlan": (True, 20., 10),
"frogpilotRadarState": (True, 20., 5),
"frogpilotSelfdriveState": (True, 100., 10),
"mapdExtendedOut": (True, 1., 1, QueueSize.MEDIUM),
"mapdIn": (True, 1., 1, QueueSize.MEDIUM),
"mapdOut": (True, 20., 20, QueueSize.MEDIUM),
}
SERVICE_LIST = {name: Service(*vals) for
idx, (name, vals) in enumerate(_services.items())}
+6 -8
View File
@@ -162,6 +162,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
{"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"CameraView", {PERSISTENT, INT, "3", "0", 2}},
{"CancelDownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"CancelModelDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"CancelThemeDownload", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"CarMake", {PERSISTENT, STRING, "mock", "mock", 0}},
@@ -210,10 +211,10 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DisableOnroadUploads", {PERSISTENT, BOOL, "0", "0", 2}},
{"DisableOpenpilotLongitudinal", {PERSISTENT, BOOL, "0", "0", 0}},
{"DiscordUsername", {PERSISTENT, STRING, "", "", 0}},
{"DisengageVolume", {PERSISTENT, INT, "101", "101", 2}},
{"DistanceButtonControl", {PERSISTENT, INT, "1", "0", 2}},
{"DistanceIconPack", {PERSISTENT, STRING, "stock", "stock", 0}},
{"DistanceIconToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"DisengageVolume", {PERSISTENT, INT, "101", "101", 2}},
{"DownloadableColors", {PERSISTENT, STRING, "", ""}},
{"DownloadableDistanceIcons", {PERSISTENT, STRING, "", ""}},
{"DownloadableIcons", {PERSISTENT, STRING, "", ""}},
@@ -221,6 +222,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DownloadableSounds", {PERSISTENT, STRING, "", ""}},
{"DownloadableWheels", {PERSISTENT, STRING, "", ""}},
{"DownloadAllModels", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DownloadMaps", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"DriverCamera", {PERSISTENT, BOOL, "0", "0", 1}},
{"DrivingModel", {PERSISTENT, STRING, "wmi-model_default", "wmi-model_default", 1}},
{"DrivingModelName", {PERSISTENT, STRING, "WMI model (Default)", "WMI model (Default)", 1}},
@@ -295,9 +297,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MapBoxRequests", {PERSISTENT, JSON, "{}", "{}"}},
{"MapboxSecretKey", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"MapDeceleration", {PERSISTENT, BOOL, "0", "0", 1}},
{"MapdLogLevel", {CLEAR_ON_MANAGER_START, STRING, "0", "0"}},
{"MapdSettings", {PERSISTENT, JSON, "{}", "{}"}},
{"MapGears", {PERSISTENT, BOOL, "0", "0", 2}},
{"MapsSelected", {PERSISTENT, JSON, "{}", "{}", 0}},
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"MaxDesiredAcceleration", {PERSISTENT, FLOAT, "4.0", "2.0", 2}},
{"MinimumBackupSize", {PERSISTENT, INT, "0", "0"}},
@@ -308,7 +310,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ModelToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"ModelUI", {PERSISTENT, BOOL, "1", "0", 2}},
{"NavigationUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"NextMapSpeedLimit", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"NNFF", {PERSISTENT, BOOL, "1", "0", 2}},
{"NNFFLite", {PERSISTENT, BOOL, "1", "0", 2}},
{"NNFFModelName", {CLEAR_ON_MANAGER_START, STRING, "", "", 0}},
@@ -327,10 +328,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"OnroadDistanceButton", {PERSISTENT, BOOL, "0", "0", 0}},
{"OnroadDistanceButtonPressed", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"openpilotMinutes", {PERSISTENT, INT, "0", "0", 0}},
{"OSMDownloadLocations", {PERSISTENT, JSON, "{}", "{}"}},
{"OSMDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"OverpassRequests", {PERSISTENT, JSON, "{}", "{}"}},
{"PathEdgeWidth", {PERSISTENT, FLOAT, "20", "0", 2}},
{"PathEdgeWidth", {PERSISTENT, FLOAT, "20.0", "0.0", 2}},
{"PathWidth", {PERSISTENT, FLOAT, "6.1", "5.9", 2}},
{"PauseAOLOnBrake", {PERSISTENT, BOOL, "0", "0", 1}},
{"PauseLateralOnSignal", {PERSISTENT, BOOL, "0", "0", 1}},
@@ -365,7 +364,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"RelaxedJerkSpeedDecrease", {PERSISTENT, FLOAT, "100.0", "100.0", 3}},
{"ReverseCruise", {PERSISTENT, BOOL, "0", "0", 1}},
{"RoadEdgesWidth", {PERSISTENT, FLOAT, "2.0", "2.0", 2}},
{"RoadName", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"RoadNameUI", {PERSISTENT, BOOL, "1", "0", 1}},
{"RotatingWheel", {PERSISTENT, BOOL, "1", "0", 1}},
{"ScreenBrightness", {PERSISTENT, INT, "101", "101", 2}},
+52 -12
View File
@@ -9,6 +9,7 @@ import time
from pathlib import Path
from cereal import messaging
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.common.time_helpers import system_time_valid
@@ -19,7 +20,7 @@ from openpilot.frogpilot.assets.theme_manager import ThemeManager
from openpilot.frogpilot.common.frogpilot_backups import backup_frogpilot
from openpilot.frogpilot.common.frogpilot_utilities import is_FrogsGoMoo, run_cmd, use_konik_server
from openpilot.frogpilot.common.frogpilot_variables import (
DISCORD_WEBHOOK_URL_REPORT, ERROR_LOGS_PATH, FROGS_GO_MOO_PATH, HD_LOGS_PATH, KONIK_LOGS_PATH, MAPD_PATH, MAPS_PATH, THEME_SAVE_PATH,
DISCORD_WEBHOOK_URL_REPORT, ERROR_LOGS_PATH, FROGS_GO_MOO_PATH, HD_LOGS_PATH, KONIK_LOGS_PATH, MAPS_PATH, THEME_SAVE_PATH,
FrogPilotVariables, get_frogpilot_toggles
)
@@ -66,6 +67,21 @@ def capture_report(discord_user, report, frogpilot_toggles):
def frogpilot_boot_functions(build_metadata, params):
params_memory = Params(memory=True)
maps_selected = params.get("MapsSelected")
if maps_selected:
try:
data = json.loads(maps_selected)
if isinstance(data, dict):
new_items = []
for nation in data.get("nations", []):
new_items.append(f"nation.{nation}")
for state in data.get("states", []):
new_items.append(f"us_state.{state}")
new_items.sort()
params.put("MapsSelected", ",".join(new_items))
except (json.JSONDecodeError, TypeError, ValueError):
pass
FrogPilotVariables()
ThemeManager(params, params_memory, boot_run=True).update_active_theme(time_validated=system_time_valid(), frogpilot_toggles=get_frogpilot_toggles(), boot_run=True)
@@ -138,12 +154,9 @@ def update_boot_logo(frogpilot=False, stock=False):
run_cmd(["sudo", "mount", "-o", f"remount,{mount_options}", "/"], "Successfully restored / mount options", "Failed to restore / mount options")
def update_maps(now, params, params_memory):
while not MAPD_PATH.exists():
time.sleep(60)
def update_maps(now, params, params_memory, manual_update=False):
maps_selected = params.get("MapsSelected")
if not maps_selected or not (maps_selected.get("nations") or maps_selected.get("states")):
if not maps_selected:
return
day = now.day
@@ -152,22 +165,49 @@ def update_maps(now, params, params_memory):
schedule = params.get("PreferredSchedule")
maps_downloaded = MAPS_PATH.exists()
if maps_downloaded and (schedule == 0 or (schedule == 1 and not is_sunday) or (schedule == 2 and not is_first)):
if maps_downloaded and (schedule == 0 or (schedule == 1 and not is_sunday) or (schedule == 2 and not is_first)) and not manual_update:
return
suffix = "th" if 11 <= day <= 13 else {1: "st", 2: "nd", 3: "rd"}.get(day % 10, "th")
todays_date = now.strftime(f"%B {day}{suffix}, %Y")
if maps_downloaded and params.get("LastMapsUpdate") == todays_date:
if maps_downloaded and params.get("LastMapsUpdate") == todays_date and not manual_update:
return
if params.get("OSMDownloadProgress") is None:
params_memory.put("OSMDownloadLocations", maps_selected)
pm = messaging.PubMaster(["mapdIn"])
sm = messaging.SubMaster(["mapdExtendedOut"])
while params.get("OSMDownloadProgress") is not None:
time.sleep(60)
time.sleep(1)
msg = messaging.new_message("mapdIn")
msg.mapdIn.type = 0
msg.mapdIn.str = maps_selected
pm.send("mapdIn", msg)
started = False
while True:
sm.update(1000)
if params_memory.get_bool("CancelDownloadMaps"):
msg = messaging.new_message("mapdIn")
msg.mapdIn.type = 27
pm.send("mapdIn", msg)
params_memory.remove("CancelDownloadMaps")
params_memory.remove("DownloadMaps")
return
if sm.updated["mapdExtendedOut"]:
progress = sm["mapdExtendedOut"].downloadProgress
if progress.active:
started = True
if not progress.active and started:
break
params.put("LastMapsUpdate", todays_date)
params_memory.remove("DownloadMaps")
def update_openpilot(thread_manager, params):
-1
View File
@@ -71,7 +71,6 @@ HD_PATH = Path("/cache/use_HD")
KONIK_LOGS_PATH = Path("/data/media/0/realdata_konik")
KONIK_PATH = Path("/cache/use_konik")
MAPD_PATH = Path("/data/media/0/osm/mapd")
MAPS_PATH = Path("/data/media/0/osm/offline")
NNFF_MODELS_PATH = Path(BASEDIR) / "frogpilot/assets/nnff_models"
@@ -9,7 +9,7 @@ from concurrent.futures import ThreadPoolExecutor
from openpilot.common.constants import CV
from openpilot.common.realtime import DT_MDL
from openpilot.frogpilot.common.frogpilot_utilities import calculate_bearing_offset, calculate_distance_to_point, is_url_pingable
from openpilot.frogpilot.common.frogpilot_utilities import calculate_bearing_offset, is_url_pingable
FREE_MAPBOX_REQUESTS = 100_000
@@ -239,7 +239,7 @@ class SpeedLimitController:
self.frogpilot_planner.params.put_nonblocking("PreviousSpeedLimit", self.target)
def update_limits(self, dashboard_speed_limit, now, time_validated, v_cruise, v_ego, sm):
self.update_map_speed_limit(v_ego)
self.update_map_speed_limit(v_ego, sm)
limits = {
"Dashboard": dashboard_speed_limit,
@@ -302,24 +302,11 @@ class SpeedLimitController:
self.speed_limit_changed_timer = 0
self.unconfirmed_speed_limit = 0
def update_map_speed_limit(self, v_ego):
if not self.frogpilot_planner.gps_position:
return
self.map_speed_limit = self.frogpilot_planner.params_memory.get("MapSpeedLimit")
next_map_speed_limit = self.frogpilot_planner.params_memory.get("NextMapSpeedLimit")
self.next_speed_limit = next_map_speed_limit.get("speedlimit", 0)
if self.next_speed_limit:
current_latitude = self.frogpilot_planner.gps_position.get("latitude")
current_longitude = self.frogpilot_planner.gps_position.get("longitude")
next_latitude = next_map_speed_limit.get("latitude")
next_longitude = next_map_speed_limit.get("longitude")
distance_to_upcoming = calculate_distance_to_point(current_latitude, current_longitude, next_latitude, next_longitude)
def update_map_speed_limit(self, v_ego, sm):
self.map_speed_limit = sm["mapdOut"].speedLimit
self.next_speed_limit = sm["mapdOut"].nextSpeedLimit
if self.next_speed_limit > 0:
if self.map_speed_limit < self.next_speed_limit:
max_lookahead = self.frogpilot_toggles.map_speed_lookahead_higher * v_ego
elif self.map_speed_limit > self.next_speed_limit:
@@ -327,7 +314,7 @@ class SpeedLimitController:
else:
max_lookahead = 0
if distance_to_upcoming < max_lookahead:
if sm["mapdOut"].nextSpeedLimitDistance < max_lookahead:
self.map_speed_limit = self.next_speed_limit
def update_override(self, v_cruise, v_cruise_diff, v_ego, v_ego_diff, sm):
+8 -5
View File
@@ -19,7 +19,7 @@ from openpilot.frogpilot.system.frogpilot_tracking import FrogPilotTracking
ASSET_CHECK_RATE = (1 / DT_MDL)
def check_assets(theme_manager, thread_manager, params_memory, frogpilot_toggles):
def check_assets(now, theme_manager, thread_manager, params, params_memory, frogpilot_toggles):
for asset_type, asset_param in THEME_COMPONENT_PARAMS.items():
asset_to_download = params_memory.get(asset_param)
if asset_to_download:
@@ -33,6 +33,9 @@ def check_assets(theme_manager, thread_manager, params_memory, frogpilot_toggles
capture_report(report_data["DiscordUser"], report_data["Issue"], vars(frogpilot_toggles))
params_memory.remove("IssueReported")
if params_memory.get_bool("DownloadMaps"):
thread_manager.run_with_lock(update_maps, (now, params, params_memory, True))
def transition_offroad(frogpilot_planner, theme_manager, thread_manager, time_validated, sm, params, frogpilot_toggles):
params.put("LastGPSPosition", json.dumps(frogpilot_planner.gps_position))
@@ -53,10 +56,10 @@ def update_checks(now, theme_manager, thread_manager, params, params_memory, fro
while not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")):
time.sleep(60)
thread_manager.run_with_lock(update_maps, (now, params, params_memory))
theme_manager.update_themes(frogpilot_toggles, boot_run)
thread_manager.run_with_lock(update_maps, (now, params, params_memory))
if frogpilot_toggles.automatic_updates:
thread_manager.run_with_lock(update_openpilot, (thread_manager, params))
@@ -89,7 +92,7 @@ def frogpilot_thread():
sm = messaging.SubMaster(["carControl", "carState", "controlsState", "deviceState", "driverMonitoringState",
"gpsLocation", "gpsLocationExternal", "liveParameters", "managerState", "modelV2",
"onroadEvents", "pandaStates", "radarState", "selfdriveState", "frogpilotCarState",
"frogpilotSelfdriveState", "frogpilotModelV2", "frogpilotOnroadEvents"],
"frogpilotSelfdriveState", "frogpilotModelV2", "frogpilotOnroadEvents", "mapdOut"],
poll="modelV2")
params = Params(return_defaults=True)
@@ -141,7 +144,7 @@ def frogpilot_thread():
started_previously = started
if rate_keeper.frame % ASSET_CHECK_RATE == 0:
check_assets(theme_manager, thread_manager, params_memory, frogpilot_toggles)
check_assets(now, theme_manager, thread_manager, params, params_memory, frogpilot_toggles)
if params_memory.get_bool("FrogPilotTogglesUpdated") or theme_manager.theme_updated:
frogpilot_toggles = update_toggles(frogpilot_variables, started, theme_manager, thread_manager, time_validated, params, frogpilot_toggles)
BIN
View File
Binary file not shown.
-153
View File
@@ -1,153 +0,0 @@
#!/usr/bin/env python3
# PFEIFER - MAPD - Modified by FrogAi for FrogPilot
import json
import os
import shutil
import stat
import subprocess
import tempfile
import time
import urllib.request
from pathlib import Path
from openpilot.common.params import Params
from openpilot.frogpilot.common.frogpilot_utilities import is_url_pingable
from openpilot.frogpilot.common.frogpilot_variables import MAPD_PATH, RESOURCES_REPO
VERSION = "v2"
GITHUB_VERSION_URL = f"https://github.com/{RESOURCES_REPO}/raw/Versions/mapd_version_{VERSION}.json"
GITLAB_VERSION_URL = f"https://gitlab.com/{RESOURCES_REPO}/-/raw/Versions/mapd_version_{VERSION}.json"
VERSION_PATH = Path("/data/media/0/osm/mapd_version")
def cleanup_temp_files():
parent = MAPD_PATH.parent
try:
if not parent.exists() or not parent.is_dir():
return
except OSError as e:
print(f"Skipping cleanup; cannot access {parent}: {e}")
return
try:
for file in parent.glob("mapd*"):
if file == MAPD_PATH or file == VERSION_PATH:
continue
if file.is_file():
try:
file.unlink()
except Exception as exception:
print(f"Failed to delete leftover file {file}: {exception}")
except OSError as exception:
print(f"Skipping cleanup in {parent} due to I/O error: {exception}")
def download():
Path(MAPD_PATH).parent.mkdir(parents=True, exist_ok=True)
while not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")):
time.sleep(60)
latest_version = get_latest_version()
urls = [
f"https://github.com/pfeiferj/openpilot-mapd/releases/download/{latest_version}/mapd",
f"https://gitlab.com/{RESOURCES_REPO}/-/raw/Mapd/{latest_version}"
]
for url in urls:
try:
with urllib.request.urlopen(url) as response:
with tempfile.NamedTemporaryFile("wb", delete=False, dir=MAPD_PATH.parent) as temp_file:
shutil.copyfileobj(response, temp_file)
temp_file_path = Path(temp_file.name)
os.fsync(temp_file.fileno())
os.chmod(temp_file_path, os.stat(temp_file_path).st_mode | stat.S_IEXEC)
os.rename(temp_file_path, MAPD_PATH)
with open(VERSION_PATH, "w") as version_file:
version_file.write(latest_version)
os.fsync(version_file.fileno())
return
except Exception as exception:
print(f"Failed to download mapd from {url}: {exception}")
if "temp_file_path" in locals() and temp_file_path.exists():
temp_file_path.unlink(missing_ok=True)
def get_latest_version():
while not (is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com")):
time.sleep(60)
for url in [GITHUB_VERSION_URL, GITLAB_VERSION_URL]:
try:
with urllib.request.urlopen(url, timeout=10) as response:
return json.loads(response.read().decode("utf-8"))["version"]
except Exception as exception:
print(f"Error fetching mapd version from {url}: {exception}")
return "v0"
def update_mapd():
if not MAPD_PATH.exists():
print(f"{MAPD_PATH} not found. Downloading...")
download()
return False
if not VERSION_PATH.exists():
print(f"{VERSION_PATH} not found. Downloading mapd...")
download()
return False
if is_url_pingable("https://github.com") or is_url_pingable("https://gitlab.com"):
try:
with open(VERSION_PATH) as version_file:
local_version = version_file.read().strip()
if local_version != get_latest_version():
print("New mapd version available. Updating...")
download()
return False
else:
return True
except Exception as exception:
print(f"Error checking version: {exception}")
return False
if not os.access(MAPD_PATH, os.X_OK):
print(f"{MAPD_PATH} is not executable. Fixing permissions...")
try:
os.chmod(MAPD_PATH, os.stat(MAPD_PATH).st_mode | stat.S_IEXEC)
except Exception as exception:
print(f"Failed to set executable permissions on {MAPD_PATH}: {exception}")
return False
return True
def mapd_thread():
params_memory = Params(memory=True)
params_memory.put("MapdLogLevel", "disabled")
while True:
try:
cleanup_temp_files()
except OSError as exception:
print(f"Cleanup errored: {exception}")
time.sleep(5)
continue
while not update_mapd():
time.sleep(60)
continue
try:
process = subprocess.Popen(str(MAPD_PATH))
process.wait()
except FileNotFoundError as error:
print(f"Subprocess failed: {error}")
download()
def main():
mapd_thread()
if __name__ == "__main__":
main()
+3 -2
View File
@@ -50,7 +50,7 @@ class MapSpeedLogger:
self.gps_location_service = get_gps_location_service(self.params)
self.sm = messaging.SubMaster(["deviceState", "frogpilotCarState", "frogpilotPlan", self.gps_location_service, "modelV2"])
self.sm = messaging.SubMaster(["deviceState", "frogpilotCarState", "frogpilotPlan", self.gps_location_service, "mapdOut", "modelV2"])
@property
def can_make_overpass_request(self):
@@ -227,7 +227,8 @@ class MapSpeedLogger:
self.previous_coordinates = None
return
road_name = self.params_memory.get("RoadName")
road_name = self.sm["mapdOut"].roadName
if not road_name or not current_speed_source:
return
+1 -1
View File
@@ -38,7 +38,7 @@ FrogPilotUIState::FrogPilotUIState(QObject *parent) : QObject(parent) {
sm = std::make_unique<SubMaster, const std::initializer_list<const char *>>({
"carControl", "deviceState", "frogpilotCarState", "frogpilotDeviceState",
"frogpilotPlan", "frogpilotRadarState", "frogpilotSelfdriveState", "liveDelay",
"liveParameters", "liveTorqueParameters", "liveTracks", "selfdriveState"
"liveParameters", "liveTorqueParameters", "liveTracks", "mapdExtendedOut", "mapdOut", "selfdriveState"
});
wifi = new WifiManager(this);
+55 -89
View File
@@ -1,5 +1,3 @@
#include <regex>
#include <QtConcurrent>
#include "frogpilot/ui/qt/offroad/maps_settings.h"
@@ -64,34 +62,6 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent, bool for
});
settingsList->addItem(removeMapsButton);
resetMapdButton = new ButtonControl(tr("Reset Downloader"), tr("RESET"),
tr("<b>Reset the map downloader.</b> Use this if downloads are stuck or failing."));
QObject::connect(resetMapdButton, &ButtonControl::clicked, [parent, this]() {
if (ConfirmationDialog::confirm(tr("Reset the map downloader? Your device will reboot afterward."), tr("Reset"), this)) {
std::thread([parent, this]() {
parent->keepScreenOn = true;
resetMapdButton->setEnabled(false);
resetMapdButton->setValue(tr("Resetting..."));
std::system("pkill mapd");
QDir("/data/media/0/osm").removeRecursively();
resetMapdButton->setValue(tr("Reset!"));
util::sleep_for(2500);
resetMapdButton->setValue(tr("Rebooting..."));
util::sleep_for(2500);
Hardware::reboot();
}).detach();
}
});
settingsList->addItem(resetMapdButton);
settingsList->addItem(mapsSize = new LabelControl(tr("Storage Used"), calculateDirectorySize(mapsFolderPath)));
ScrollView *settingsPanel = new ScrollView(settingsList, this);
@@ -138,13 +108,10 @@ FrogPilotMapsPanel::FrogPilotMapsPanel(FrogPilotSettingsWindow *parent, bool for
downloadMapsButton->showDescription();
preferredSchedule->showDescription();
removeMapsButton->showDescription();
resetMapdButton->showDescription();
selectMaps->showDescription();
}
std::string mapsSelected = params.get("MapsSelected");
hasMapsSelected = !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("nations").toArray().isEmpty();
hasMapsSelected |= !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("states").toArray().isEmpty();
hasMapsSelected = !params.get("MapsSelected").empty();
mapsLayout->setCurrentWidget(settingsPanel);
});
@@ -156,7 +123,6 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
downloadMapsButton->showDescription();
preferredSchedule->showDescription();
removeMapsButton->showDescription();
resetMapdButton->showDescription();
selectMaps->showDescription();
}
@@ -165,17 +131,23 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
FrogPilotUIState &fs = *frogpilotUIState();
FrogPilotUIScene &frogpilot_scene = fs.frogpilot_scene;
SubMaster &fpsm = *(fs.sm);
std::string mapsSelected = params.get("MapsSelected");
hasMapsSelected = !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("nations").toArray().isEmpty();
hasMapsSelected |= !QJsonDocument::fromJson(QByteArray::fromStdString(mapsSelected)).object().value("states").toArray().isEmpty();
const cereal::MapdExtendedOut::Reader &mapdExtendedOut = fpsm["mapdExtendedOut"].getMapdExtendedOut();
const cereal::MapdDownloadProgress::Reader &downloadProgress = mapdExtendedOut.getDownloadProgress();
bool mapDownloadActive = downloadProgress.getActive();
int mapDownloadDownloaded = downloadProgress.getDownloadedFiles();
int mapDownloadTotal = downloadProgress.getTotalFiles();
hasMapsSelected = !params.get("MapsSelected").empty();
bool parked = !scene.started || frogpilot_scene.parked || parent->isFrogsGoMoo;
removeMapsButton->setVisible(mapsFolderPath.exists());
std::string osmDownloadProgress = params.get("OSMDownloadProgress");
if (!osmDownloadProgress.empty()) {
if (mapDownloadActive) {
downloadMapsButton->setText(tr("CANCEL"));
downloadStatus->setText(tr("Calculating..."));
@@ -183,9 +155,8 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
lastMapsDownload->setVisible(false);
removeMapsButton->setVisible(false);
resetMapdButton->setVisible(false);
updateDownloadLabels(osmDownloadProgress);
updateDownloadLabels(mapDownloadDownloaded, mapDownloadTotal);
} else {
downloadMapsButton->setEnabled(!cancellingDownload && hasMapsSelected && frogpilot_scene.online && parked);
downloadMapsButton->setValue(frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
@@ -194,24 +165,33 @@ void FrogPilotMapsPanel::showEvent(QShowEvent *event) {
void FrogPilotMapsPanel::updateState(const UIState &s, const FrogPilotUIState &fs) {
if (!isVisible() || s.sm->frame % (UI_FREQ / 2) != 0) {
if (!isVisible()) {
return;
}
const FrogPilotUIScene &frogpilot_scene = fs.frogpilot_scene;
const UIScene &scene = s.scene;
const SubMaster &fpsm = *(fs.sm);
const cereal::MapdExtendedOut::Reader &mapdExtendedOut = fpsm["mapdExtendedOut"].getMapdExtendedOut();
const cereal::MapdDownloadProgress::Reader &downloadProgress = mapdExtendedOut.getDownloadProgress();
bool mapDownloadActive = downloadProgress.getActive();
bool parked = !scene.started || frogpilot_scene.parked || parent->isFrogsGoMoo;
std::string osmDownloadProgress = params.get("OSMDownloadProgress");
if (!osmDownloadProgress.empty() && !cancellingDownload) {
updateDownloadLabels(osmDownloadProgress);
int mapDownloadDownloaded = downloadProgress.getDownloadedFiles();
int mapDownloadTotal = downloadProgress.getTotalFiles();
if (mapDownloadActive && !cancellingDownload) {
updateDownloadLabels(mapDownloadDownloaded, mapDownloadTotal);
} else if (downloadMapsButton->text() == tr("CANCEL")) {
updateDownloadLabels(mapDownloadDownloaded, mapDownloadTotal);
} else {
downloadMapsButton->setEnabled(!cancellingDownload && hasMapsSelected && frogpilot_scene.online && parked);
downloadMapsButton->setValue(frogpilot_scene.online ? (parked ? "" : tr("Not parked")) : tr("Offline..."));
}
parent->keepScreenOn = !osmDownloadProgress.empty();
parent->keepScreenOn = mapDownloadActive;
}
void FrogPilotMapsPanel::cancelDownload() {
@@ -224,10 +204,8 @@ void FrogPilotMapsPanel::cancelDownload() {
downloadStatus->setText(tr("Calculating..."));
downloadTimeElapsed->setText(tr("Calculating..."));
params.remove("OSMDownloadProgress");
params_memory.remove("OSMDownloadLocations");
std::system("pkill mapd");
params_memory.putBool("CancelDownloadMaps", true);
params_memory.remove("DownloadMaps");
QTimer::singleShot(2500, [this]() {
cancellingDownload = false;
@@ -242,7 +220,6 @@ void FrogPilotMapsPanel::cancelDownload() {
lastMapsDownload->setVisible(true);
removeMapsButton->setVisible(mapsFolderPath.exists());
resetMapdButton->setVisible(true);
update();
});
@@ -260,53 +237,42 @@ void FrogPilotMapsPanel::startDownload() {
lastMapsDownload->setVisible(false);
removeMapsButton->setVisible(false);
resetMapdButton->setVisible(false);
elapsedTime.start();
startTime = QDateTime::currentDateTime();
params_memory.put("OSMDownloadLocations", params.get("MapsSelected"));
params_memory.putBool("DownloadMaps", true);
}
void FrogPilotMapsPanel::updateDownloadLabels(std::string &osmDownloadProgress) {
static std::regex fileStatusRegex(R"("total_files":(\d+),.*"downloaded_files":(\d+))");
void FrogPilotMapsPanel::updateDownloadLabels(int downloadedFiles, int totalFiles) {
if (downloadedFiles == totalFiles && totalFiles != 0) {
downloadMapsButton->setText(tr("DOWNLOAD"));
lastMapsDownload->setText(formatCurrentDate());
std::smatch match;
if (std::regex_search(osmDownloadProgress, match, fileStatusRegex)) {
int totalFiles = std::stoi(match[1].str());
int downloadedFiles = std::stoi(match[2].str());
downloadETA->setVisible(false);
downloadStatus->setVisible(false);
downloadTimeElapsed->setVisible(false);
if (downloadedFiles == totalFiles) {
downloadMapsButton->setText(tr("DOWNLOAD"));
lastMapsDownload->setText(formatCurrentDate());
lastMapsDownload->setVisible(true);
removeMapsButton->setVisible(true);
downloadETA->setVisible(false);
downloadStatus->setVisible(false);
downloadTimeElapsed->setVisible(false);
params.put("LastMapsUpdate", formatCurrentDate().toStdString());
lastMapsDownload->setVisible(true);
removeMapsButton->setVisible(true);
resetMapdButton->setVisible(true);
update();
params.put("LastMapsUpdate", formatCurrentDate().toStdString());
params.remove("OSMDownloadProgress");
update();
return;
}
static int previousDownloadedFiles = 0;
if (downloadedFiles != previousDownloadedFiles) {
std::thread([this]() {
mapsSize->setText(calculateDirectorySize(mapsFolderPath));
}).detach();
}
downloadETA->setText(QString("%1").arg(formatETA(elapsedTime.elapsed(), downloadedFiles, previousDownloadedFiles, totalFiles, startTime)));
downloadStatus->setText(QString("%1 / %2 (%3%)").arg(downloadedFiles).arg(totalFiles).arg((downloadedFiles * 100) / totalFiles));
downloadTimeElapsed->setText(formatElapsedTime(elapsedTime.elapsed()));
previousDownloadedFiles = downloadedFiles;
return;
}
static int previousDownloadedFiles = 0;
if (downloadedFiles != previousDownloadedFiles) {
std::thread([this]() {
mapsSize->setText(calculateDirectorySize(mapsFolderPath));
}).detach();
}
downloadETA->setText(QString("%1").arg(formatETA(elapsedTime.elapsed(), downloadedFiles, previousDownloadedFiles, totalFiles, startTime)));
downloadStatus->setText(QString("%1 / %2 (%3%)").arg(downloadedFiles).arg(totalFiles).arg((downloadedFiles * 100) / (totalFiles == 0 ? 1 : totalFiles)));
downloadTimeElapsed->setText(formatElapsedTime(elapsedTime.elapsed()));
previousDownloadedFiles = downloadedFiles;
}
+1 -2
View File
@@ -18,7 +18,7 @@ protected:
private:
void cancelDownload();
void startDownload();
void updateDownloadLabels(std::string &osmDownloadProgress);
void updateDownloadLabels(int downloadedFiles, int totalFiles);
void updateState(const UIState &s, const FrogPilotUIState &fs);
bool cancellingDownload;
@@ -27,7 +27,6 @@ private:
ButtonControl *downloadMapsButton;
ButtonControl *removeMapsButton;
ButtonControl *resetMapdButton;
ButtonParamControl *preferredSchedule;
@@ -134,6 +134,7 @@ void FrogPilotAnnotatedCameraWidget::updateState(const UIState &s, const FrogPil
const cereal::FrogPilotCarState::Reader &frogpilotCarState = fpsm["frogpilotCarState"].getFrogpilotCarState();
const cereal::FrogPilotPlan::Reader &frogpilotPlan = fpsm["frogpilotPlan"].getFrogpilotPlan();
const cereal::FrogPilotSelfdriveState::Reader &frogpilotSelfdriveState = fpsm["frogpilotSelfdriveState"].getFrogpilotSelfdriveState();
const cereal::MapdOut::Reader &mapdOut = fpsm["mapdOut"].getMapdOut();
const cereal::ModelDataV2::Reader &modelV2 = sm["modelV2"].getModelV2();
const cereal::SelfdriveState::Reader &selfdriveState = sm["selfdriveState"].getSelfdriveState();
@@ -177,7 +178,7 @@ void FrogPilotAnnotatedCameraWidget::updateState(const UIState &s, const FrogPil
nextSpeedLimit = frogpilotPlan.getSlcNextSpeedLimit();
redLight = frogpilotPlan.getRedLight();
roadCurvature = frogpilotPlan.getRoadCurvature();
roadName = QString::fromStdString(params_memory.get("RoadName"));
roadName = QString::fromStdString(mapdOut.getRoadName());
slcOverriddenSpeed = frogpilotPlan.getSlcOverriddenSpeed();
speedLimit = slcOverriddenSpeed != 0 ? slcOverriddenSpeed : frogpilotPlan.getSlcSpeedLimit();
speedLimitChanged = frogpilotPlan.getSpeedLimitChanged();
+22 -21
View File
@@ -1,7 +1,3 @@
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include "frogpilot/ui/qt/widgets/navigation_functions.h"
MapSelectionControl::MapSelectionControl(const QMap<QString, QString> &map, bool isCountry) : selectionType(isCountry ? "nations" : "states") {
@@ -28,11 +24,15 @@ MapSelectionControl::MapSelectionControl(const QMap<QString, QString> &map, bool
}
void MapSelectionControl::loadSelectedMaps() {
QJsonObject existingMaps = QJsonDocument::fromJson(QByteArray::fromStdString(params.get("MapsSelected"))).object();
QString mapsSelected = QString::fromStdString(params.get("MapsSelected"));
QStringList mapList = mapsSelected.split(",", QString::SkipEmptyParts);
QString prefix = (selectionType == "nations") ? "nation." : "us_state.";
QSet<QString> selectedMaps;
for (const QJsonValue &value : existingMaps.value(selectionType).toArray()) {
selectedMaps.insert(value.toString());
for (const QString &map : mapList) {
if (map.startsWith(prefix)) {
selectedMaps.insert(map.mid(prefix.length()));
}
}
for (QAbstractButton *button : mapButtons->buttons()) {
@@ -41,22 +41,23 @@ void MapSelectionControl::loadSelectedMaps() {
}
void MapSelectionControl::updateSelectedMaps() {
QJsonObject existingMaps = QJsonDocument::fromJson(QByteArray::fromStdString(params.get("MapsSelected"))).object();
QString mapsSelected = QString::fromStdString(params.get("MapsSelected"));
QStringList mapList = mapsSelected.split(",", QString::SkipEmptyParts);
QString prefix = (selectionType == "nations") ? "nation." : "us_state.";
QSet<QString> selectedMaps;
for (const QJsonValue &value : existingMaps.value(selectionType).toArray()) {
selectedMaps.insert(value.toString());
}
for (QAbstractButton *button : mapButtons->buttons()) {
QString mapKey = button->property("mapKey").toString();
if (button->isChecked()) {
selectedMaps.insert(mapKey);
} else {
selectedMaps.remove(mapKey);
QStringList newMapList;
for (const QString &map : mapList) {
if (!map.startsWith(prefix)) {
newMapList.append(map);
}
}
existingMaps[selectionType] = QJsonArray::fromStringList(selectedMaps.values());
params.putNonBlocking("MapsSelected", QJsonDocument(existingMaps).toJson(QJsonDocument::Compact).toStdString());
for (QAbstractButton *button : mapButtons->buttons()) {
if (button->isChecked()) {
newMapList.append(prefix + button->property("mapKey").toString());
}
}
newMapList.sort();
params.putNonBlocking("MapsSelected", newMapList.join(",").toStdString());
}
+1 -1
View File
@@ -133,7 +133,7 @@ elif TICI:
procs.append(NativeProcess("ui", "selfdrive/ui", ["./ui"], always_run, watchdog_max_dt=5)),
procs += [
PythonProcess("frogpilot_process", "frogpilot.frogpilot_process", always_run),
PythonProcess("mapd", "frogpilot.navigation.mapd", always_run),
NativeProcess("mapd", "frogpilot/navigation", ["./mapd"], always_run),
PythonProcess("speed_limit_filler", "frogpilot.system.speed_limit_filler", run_speed_limit_filler),
]