Newer
Older
RobotCar / src / pc / steering / auto_params.py
"""
auto_params
パラメータの自動保存・読み込みを管理するモジュール
アプリ起動時に前回のパラメータを復元し,変更時に自動保存する

ファイル構成:
    params/
    ├── control.json              PD 制御 + 最後に使用した手法
    ├── detect_current.json       現行手法の画像処理パラメータ
    ├── detect_blackhat.json      案A の画像処理パラメータ
    ├── detect_dual_norm.json     案B の画像処理パラメータ
    └── detect_robust.json        案C の画像処理パラメータ
"""

import json
from dataclasses import asdict
from pathlib import Path

from pc.steering.pd_control import PdParams
from pc.vision.line_detector import ImageParams

# パラメータ保存ディレクトリ
_PARAMS_DIR: Path = (
    Path(__file__).resolve().parent.parent.parent.parent
    / "params"
)

# PD 制御パラメータファイル
_CONTROL_FILE: Path = _PARAMS_DIR / "control.json"

# 検出手法ごとのファイル名
_DETECT_FILES: dict[str, str] = {
    "current": "detect_current.json",
    "blackhat": "detect_blackhat.json",
    "dual_norm": "detect_dual_norm.json",
    "robust": "detect_robust.json",
}


def save_control(
    params: PdParams, method: str,
) -> None:
    """PD 制御パラメータと最後に使用した手法を保存する

    Args:
        params: PD 制御パラメータ
        method: 最後に使用した検出手法の識別子
    """
    _PARAMS_DIR.mkdir(exist_ok=True)
    data = asdict(params)
    data["last_method"] = method
    _write_json(_CONTROL_FILE, data)


def load_control() -> tuple[PdParams, str]:
    """PD 制御パラメータと最後に使用した手法を読み込む

    Returns:
        (PD 制御パラメータ, 最後に使用した手法の識別子)
    """
    if not _CONTROL_FILE.exists():
        return PdParams(), "current"

    data = _read_json(_CONTROL_FILE)
    method = data.pop("last_method", "current")
    known = PdParams.__dataclass_fields__
    filtered = {
        k: v for k, v in data.items()
        if k in known
    }
    return PdParams(**filtered), method


def save_detect_params(
    method: str, params: ImageParams,
) -> None:
    """検出手法のパラメータを保存する

    Args:
        method: 検出手法の識別子
        params: 画像処理パラメータ
    """
    filename = _DETECT_FILES.get(method)
    if filename is None:
        return
    _PARAMS_DIR.mkdir(exist_ok=True)
    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)


def _write_json(path: Path, data: dict) -> None:
    """JSON ファイルに書き込む"""
    with open(path, "w", encoding="utf-8") as f:
        json.dump(
            data, f, ensure_ascii=False, indent=2,
        )


def _read_json(path: Path) -> dict:
    """JSON ファイルを読み込む"""
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)