"""
auto_params
パラメータの自動保存・読み込みを管理するモジュール
アプリ起動時に前回のパラメータを復元し,変更時に自動保存する
ファイル構成:
params/
├── control.json PD 制御 + 最後に使用した手法
├── pursuit.json パシュート制御パラメータ
├── ts_pd.json Theil-Sen PD 制御パラメータ
├── recovery.json コースアウト復帰パラメータ
├── overlay.json オーバーレイ表示フラグ
├── detect_current.json 現行手法の二値化パラメータ
├── detect_blackhat.json 案A の二値化パラメータ
├── detect_dual_norm.json 案B の二値化パラメータ
└── detect_robust.json 案C の二値化パラメータ
"""
from dataclasses import asdict
from common.json_utils import PARAMS_DIR, read_json, write_json
from pc.steering.pd_control import PdParams
from pc.steering.pursuit_control import PursuitParams
from pc.steering.recovery import RecoveryParams
from pc.steering.ts_pd_control import TsPdParams
from pc.vision.line_detector import ImageParams
from pc.vision.overlay import OverlayFlags
# PD 制御パラメータファイル
_CONTROL_FILE = PARAMS_DIR / "control.json"
# パシュート制御パラメータファイル
_PURSUIT_FILE = PARAMS_DIR / "pursuit.json"
# Theil-Sen PD 制御パラメータファイル
_TS_PD_FILE = PARAMS_DIR / "ts_pd.json"
# コースアウト復帰パラメータファイル
_RECOVERY_FILE = PARAMS_DIR / "recovery.json"
# オーバーレイ表示フラグファイル
_OVERLAY_FILE = PARAMS_DIR / "overlay.json"
# 検出手法ごとのファイル名
_DETECT_FILES: dict[str, str] = {
"current": "detect_current.json",
"blackhat": "detect_blackhat.json",
"dual_norm": "detect_dual_norm.json",
"robust": "detect_robust.json",
"valley": "detect_valley.json",
}
def save_control(
params: PdParams,
method: str,
steering_method: str = "pd",
) -> None:
"""PD 制御パラメータと最後に使用した手法を保存する
Args:
params: PD 制御パラメータ
method: 最後に使用した検出手法の識別子
steering_method: 最後に使用した制御手法("pd" or "pursuit")
"""
data = asdict(params)
data["last_method"] = method
data["last_steering_method"] = steering_method
write_json(_CONTROL_FILE, data)
def load_control() -> tuple[PdParams, str, str]:
"""PD 制御パラメータと最後に使用した手法を読み込む
Returns:
(PD 制御パラメータ, 検出手法の識別子, 制御手法の識別子)
"""
if not _CONTROL_FILE.exists():
return PdParams(), "current", "pd"
data = read_json(_CONTROL_FILE)
method = data.pop("last_method", "current")
steering_method = data.pop(
"last_steering_method", "pd",
)
known = PdParams.__dataclass_fields__
filtered = {
k: v for k, v in data.items()
if k in known
}
return PdParams(**filtered), method, steering_method
def save_pursuit(params: PursuitParams) -> None:
"""パシュート制御パラメータを保存する
Args:
params: パシュート制御パラメータ
"""
write_json(_PURSUIT_FILE, asdict(params))
def load_pursuit() -> PursuitParams:
"""パシュート制御パラメータを読み込む
Returns:
パシュート制御パラメータ(ファイルがない場合はデフォルト)
"""
if not _PURSUIT_FILE.exists():
return PursuitParams()
data = read_json(_PURSUIT_FILE)
known = PursuitParams.__dataclass_fields__
filtered = {
k: v for k, v in data.items()
if k in known
}
return PursuitParams(**filtered)
def save_ts_pd(params: TsPdParams) -> None:
"""Theil-Sen PD 制御パラメータを保存する
Args:
params: Theil-Sen PD 制御パラメータ
"""
write_json(_TS_PD_FILE, asdict(params))
def load_ts_pd() -> TsPdParams:
"""Theil-Sen PD 制御パラメータを読み込む
Returns:
Theil-Sen PD 制御パラメータ(ファイルがない場合はデフォルト)
"""
if not _TS_PD_FILE.exists():
return TsPdParams()
data = read_json(_TS_PD_FILE)
known = TsPdParams.__dataclass_fields__
filtered = {
k: v for k, v in data.items()
if k in known
}
return TsPdParams(**filtered)
def save_recovery(params: RecoveryParams) -> None:
"""コースアウト復帰パラメータを保存する
Args:
params: コースアウト復帰パラメータ
"""
write_json(_RECOVERY_FILE, asdict(params))
def load_recovery() -> RecoveryParams:
"""コースアウト復帰パラメータを読み込む
Returns:
復帰パラメータ(ファイルがない場合はデフォルト)
"""
if not _RECOVERY_FILE.exists():
return RecoveryParams()
data = read_json(_RECOVERY_FILE)
known = RecoveryParams.__dataclass_fields__
filtered = {
k: v for k, v in data.items()
if k in known
}
return RecoveryParams(**filtered)
def save_overlay(flags: OverlayFlags) -> None:
"""オーバーレイ表示フラグを保存する
Args:
flags: オーバーレイ表示フラグ
"""
write_json(_OVERLAY_FILE, asdict(flags))
def load_overlay() -> OverlayFlags:
"""オーバーレイ表示フラグを読み込む
Returns:
オーバーレイ表示フラグ(ファイルがない場合はデフォルト)
"""
if not _OVERLAY_FILE.exists():
return OverlayFlags()
data = read_json(_OVERLAY_FILE)
known = OverlayFlags.__dataclass_fields__
filtered = {
k: v for k, v in data.items()
if k in known
}
return OverlayFlags(**filtered)
def save_detect_params(
method: str, params: ImageParams,
) -> None:
"""検出手法のパラメータを保存する
Args:
method: 検出手法の識別子
params: 二値化パラメータ
"""
filename = _DETECT_FILES.get(method)
if filename is None:
return
data = asdict(params)
data["method"] = method
write_json(PARAMS_DIR / filename, data)
def load_detect_params(method: str) -> ImageParams:
"""検出手法のパラメータを読み込む
Args:
method: 検出手法の識別子
Returns:
二値化パラメータ(ファイルがない場合はデフォルト)
"""
filename = _DETECT_FILES.get(method)
if filename is None:
return ImageParams(method=method)
path = PARAMS_DIR / filename
if not path.exists():
return ImageParams(method=method)
data = read_json(path)
known = ImageParams.__dataclass_fields__
filtered = {
k: v for k, v in data.items()
if k in known
}
filtered["method"] = method
return ImageParams(**filtered)