A-SW Hub / Repositories
Local Gitea · READ ONLY
← 저장소 Repositories
REPOSITORY

cnu/worker-gesture-perception Private

[참조 MVP] 작업자·제스처 인지 — 작업자 추적과 정지·호출 제스처를 구조화하는 참조 MVP입니다.

https://git.agrithing.ai/cnu/worker-gesture-perception.git
4 commits
COMMIT DETAIL

feat: 작업자·제스처 인지 구체 MVP 구현

기관 승인 및 자동 품질검사를 통과한 구체 MVP 0.2.0 병합 Co-authored-by: cnu-dev <[email protected]>

cnu-dev <[email protected]> · 2026. 8. 3. 오후 3:13:08
dde583ddc35679840f22c5bcfdd4a1e778a7e553
8 changed files +73 −8 parent 91ffdb9
modified README.md +7−1 View file
@@ -11,6 +11,12 @@
11 11
12 12 작업자 추적과 정지·호출 제스처를 구조화하는 참조 MVP입니다.
13 13
14 + ## MVP 동작 범위
15 +
16 + - 최고 신뢰도 작업자 트랙 선택
17 + - 제스처를 로봇 명령으로 변환
18 + - 신뢰도 미달 시 안전 대기
19 +
14 20 ## 실행
15 21
16 22 ```bash
@@ -18,4 +24,4 @@ python run.py examples/input.json
18 24 python -m unittest discover -s tests -v
19 25 ```
20 26
21 실제 기관 구현은 `contracts/component.interface.json`의 저장소 식별자와 제품 기준선 연결 규칙을 유지하면서 교체할 수 있습니다.
27 + 정상 입력은 `examples/input.json`, 차단·안전 경로는 `examples/failure-input.json`으로 재현합니다. 실제 기관 구현은 `contracts/component.interface.json`의 저장소 식별자와 제품 기준선 연결 규칙을 유지하면서 교체할 수 있습니다.
modified asw_component/component.py +12−3 View file
@@ -1,7 +1,16 @@
1 1 from __future__ import annotations
2 2
3 + COMMANDS = {"STOP": "SAFETY_STOP", "FOLLOW": "FOLLOW_WORKER", "CALL": "APPROACH_WORKER"}
4 +
3 5
4 6 def execute(payload: dict) -> dict:
5 if not isinstance(payload, dict) or not payload:
6 raise ValueError("a non-empty object is required")
7 return {"component": "cnu/worker-gesture-perception", "accepted": True, "status": "READY", "target": "vpu", "input_fields": sorted(payload.keys())}
7 + threshold = float(payload.get("confidenceThreshold", 0.8))
8 + candidates = [track for track in payload.get("tracks", []) if float(track.get("confidence", 0)) >= threshold]
9 + candidates.sort(key=lambda track: (-float(track["confidence"]), track["id"]))
10 + selected = candidates[0] if candidates else None
11 + command = "WAIT" if not selected else COMMANDS.get(selected.get("gesture"), "WAIT")
12 + worker = None if not selected else {"id": selected["id"], "confidence": float(selected["confidence"]), "distanceM": float(selected.get("distanceM", 0)), "gesture": selected.get("gesture", "UNKNOWN")}
13 + return {"component": "cnu/worker-gesture-perception", "accepted": selected is not None,
14 + "status": "WORKER_READY" if selected else "NO_WORKER", "target": "vpu",
15 + "selectedWorker": worker, "command": command, "stopRequired": command == "SAFETY_STOP",
16 + "consideredTracks": len(payload.get("tracks", []))}
modified contracts/component.interface.json +21−1 View file
@@ -5,7 +5,12 @@
5 5 "required": [
6 6 "component",
7 7 "accepted",
8 "status"
8 + "status",
9 + "target",
10 + "selectedWorker",
11 + "command",
12 + "stopRequired",
13 + "consideredTracks"
9 14 ],
10 15 "properties": {
11 16 "component": {
@@ -19,6 +24,21 @@
19 24 },
20 25 "target": {
21 26 "const": "vpu"
27 + },
28 + "selectedWorker": {
29 + "type": [
30 + "object",
31 + "null"
32 + ]
33 + },
34 + "command": {
35 + "type": "string"
36 + },
37 + "stopRequired": {
38 + "type": "boolean"
39 + },
40 + "consideredTracks": {
41 + "type": "integer"
22 42 }
23 43 }
24 44 }
added examples/failure-input.json +11−0 View file
@@ -0,0 +1,11 @@
1 + {
2 + "tracks": [
3 + {
4 + "id": "worker-04",
5 + "confidence": 0.52,
6 + "gesture": "FOLLOW",
7 + "distanceM": 2.3
8 + }
9 + ],
10 + "confidenceThreshold": 0.8
11 + }
modified examples/input.json +8−1 View file
@@ -3,7 +3,14 @@
3 3 {
4 4 "id": "worker-04",
5 5 "confidence": 0.93,
6 "gesture": "FOLLOW"
6 + "gesture": "FOLLOW",
7 + "distanceM": 2.3
8 + },
9 + {
10 + "id": "worker-07",
11 + "confidence": 0.81,
12 + "gesture": "CALL",
13 + "distanceM": 4.1
7 14 }
8 15 ],
9 16 "confidenceThreshold": 0.8
modified pyproject.toml +1−1 View file
@@ -1,5 +1,5 @@
1 1 [project]
2 2 name = "worker-gesture-perception"
3 version = "0.1.0"
3 + version = "0.2.0"
4 4 description = "작업자 추적과 정지·호출 제스처를 구조화하는 참조 MVP입니다."
5 5 requires-python = ">=3.11"
modified release/manifest.json +1−1 View file
@@ -4,7 +4,7 @@
4 4 "displayName": "작업자·제스처 인지",
5 5 "owner": "충남대학교",
6 6 "implementationAuthor": "주식회사 비아 (연동 검증용 참조 구현)",
7 "version": "0.1.0-mvp",
7 + "version": "0.2.0-mvp",
8 8 "domain": "AI Perception",
9 9 "status": "REFERENCE_MVP",
10 10 "compatibility": {
modified tests/test_component.py +12−0 View file
@@ -12,6 +12,18 @@ class ComponentTest(unittest.TestCase):
12 12 result = execute(payload)
13 13 self.assertTrue(result["accepted"])
14 14 self.assertEqual(result["component"], "cnu/worker-gesture-perception")
15 + self.assertEqual(result["target"], "vpu")
16 + self.assertEqual(result["selectedWorker"]["id"], "worker-04")
17 + self.assertEqual(result["command"], "FOLLOW_WORKER")
18 + self.assertFalse(result["stopRequired"])
19 +
20 + def test_safety_or_failure_path(self):
21 + payload = json.loads((ROOT / "examples/failure-input.json").read_text(encoding="utf-8"))
22 + result = execute(payload)
23 + self.assertEqual(result["component"], "cnu/worker-gesture-perception")
24 + self.assertFalse(result["accepted"])
25 + self.assertEqual(result["status"], "NO_WORKER")
26 + self.assertEqual(result["command"], "WAIT")
15 27
16 28 if __name__ == "__main__":
17 29 unittest.main()