asw_component/__init__.py +3−0 View file@@ -0,0 +1,3 @@
1 +
from .component import execute 2 +
3 +
__all__ = ["execute"][참조 MVP] 작업경로 추종 A-SW — 현재 자세와 경로에서 Pure Pursuit 방식의 조향 명령을 계산합니다.
https://git.agrithing.ai/kitech/path-tracking-asw.git a0afd4d 870c250 18a2162 2dd63b7 91d4eca 767167a 91d4eca535092cd74b03e8066ab54dcdf69b3a59 asw_component/__init__.py +3−0 View filefrom .component import execute__all__ = ["execute"]asw_component/component.py +20−0 View filefrom __future__ import annotationsimport mathdef execute(payload: dict) -> dict: pose, path = payload["pose"], payload["path"] lookahead = float(payload.get("lookahead_m", 2.5)) wheelbase = float(payload.get("wheelbase_m", 2.1)) if not path or lookahead <= 0 or wheelbase <= 0: raise ValueError("path, lookahead and wheelbase are required") x, y, heading = float(pose["x"]), float(pose["y"]), float(pose["heading_rad"]) target = path[-1] for point in path: if math.hypot(point[0] - x, point[1] - y) >= lookahead: target = point break alpha = math.atan2(target[1] - y, target[0] - x) - heading steering = math.atan2(2 * wheelbase * math.sin(alpha), max(lookahead, 0.01)) cross_track = min(math.hypot(px-x, py-y) for px, py in path) return {"target": target, "steering_rad": round(steering, 5), "cross_track_error_m": round(cross_track, 3)}examples/input.json +23−0 View file{ "pose": { "x": 0, "y": 0, "heading_rad": 0 }, "path": [ [ 0, 0 ], [ 5, 1 ], [ 10, 1 ] ], "lookahead_m": 3, "wheelbase_m": 2.1}pyproject.toml +8−0 View file[project]name = "path_tracking_asw"version = "0.1.0"description = "현재 자세와 경로에서 Pure Pursuit 방식의 조향 명령을 계산합니다."requires-python = ">=3.11"[tool.unittest]test-path = "tests"run.py +10−0 View filefrom __future__ import annotationsimport jsonimport sysfrom asw_component import executeif __name__ == "__main__": path = sys.argv[1] if len(sys.argv) > 1 else None with open(path, encoding="utf-8") if path else sys.stdin as source: payload = json.load(source) print(json.dumps(execute(payload), ensure_ascii=False, indent=2))