5.9 20 Hz 폐루프 추론
그림 5-3. sensor/control loop와 policy worker를 분리하고 action queue, safety filter, watchdog을 거치는 폐루프.
5.9.1 주기와 deadline
20 Hz의 period는 50 ms다. 한 cycle의 예산은 capture, preprocessing, inference/queue, safety filter, communication을 포함한다.
VLA inference가 50 ms를 넘으면 매 cycle 동기 추론은 deadline을 놓친다. 대안은 다음과 같다.
- action chunk를 queue에 넣고 control loop가 소비한다.
- policy worker를 별 thread/process/machine에 둔다.
- execution horizon이 소진되기 전에 다음 chunk를 요청한다.
- inference가 늦으면 사전에 정한 HOLD/STOP 계약으로 전환한다. 이전 명령 유지는 유효한 절대 위치 목표처럼 해당 의미가 허용되는 경우에만 제한 시간 안에서 사용한다. delta·속도·토글 명령의 반복 송신은 정지를 뜻하지 않으며 무조건 재사용하지 않는다.
LeRobot은 Asynchronous Inference와 RTC 방식 안내를 제공한다. 사용 API는 버전에 따라 달라질 수 있으므로 개념과 실제 CLI를 구분한다.
5.9.2 receding horizon
chunk 전체를 끝까지 open-loop로 실행하지 않고 첫 개만 실행한 뒤 새 관측으로 재계획한다. 이면 가장 폐루프적이지만 inference rate가 높다. latency와 환경 변화 속도에 맞춰 execution horizon을 정한다.
5.9.3 temporal ensembling
시점 에서 예측한 chunk가 현재 step 의 action도 포함할 수 있다. 여러 예측을 가중 평균한다.
code/temporal_ensemble.py가 이를 구현한다. 여기서 j는 현재 step에서 예측 생성 step까지의 나이이며 양의 λ는 최신 예측에 더 큰 가중치를 준다. 이는 이 책의 교육용 계약이다. LeRobot ACT 구현의 ACTTemporalEnsembler는 가장 오래된 후보를 인덱스 0으로 두어 양의 temporal_ensemble_coeff일 때 오래된 후보를 더 크게 반영한다. 계수의 부호와 후보 순서가 다르므로 이 예제의 값을 그대로 ACT 설정에 옮기지 않는다. 평균은 discontinuity를 줄일 수 있지만 multimodal 행동의 서로 다른 mode를 섞으면 위험한 중간 행동을 만들 수 있다. grasp 전환점처럼 mode switch가 있는 구간은 history를 reset하거나 phase-aware ensemble을 사용한다.
후보를 무조건 평균하지 않는다. 각 proposal에 schema, unit, finite, source timestamp, task/phase, 기본 hard limit 검사를 먼저 적용하고 stale/invalid proposal을 버린다. 유효 후보만 ensemble/filter한 뒤 최종 결과에 rate, joint/workspace, collision 검사를 다시 적용한다.
5.9.4 safety filter와 watchdog
모델 출력은 곧바로 motor command가 아니다. 최소한 다음 단계를 거친다.
- inverse normalization
- NaN/Inf 검사
- joint/workspace limit clamp 또는 reject
- velocity/acceleration/jerk limit
- self/environment collision check
- timestamp freshness 확인
- watchdog heartbeat
- command 전송
code/closed_loop_20hz.py는 hardware-free mock loop로 joint limit과 per-cycle delta limit을 보여 준다. 제안·이전 명령·제한 벡터의 shape와 유한값을 clamp 전에 확인한다. Inf를 먼저 clamp하면 유한한 한계값으로 바뀌어 오류가 숨기므로 순서를 바꾸지 않는다. 이전 명령이 이미 범위 밖이면 자동 복구를 시도하지 않고 예외로 거부하며, 이 예제는 실제 모터 송신을 하지 않는다. 실제 안전 정지는 software exception 하나에 의존하지 않고 hardware E-stop과 독립 watchdog을 둔다.
잠깐 점검 — 부드러운 출력과 안전한 출력은 같은가
- Temporal ensembling으로 행동이 매끄러워졌다면 관절 한계 검사를 생략해도 되는가?
- 값과 단위가 올바른 action이라도 source timestamp가 오래되었다면 왜 실행하면 안 되는가?
확인 포인트: 평균화는 불연속을 줄일 뿐 물리 한계를 보장하지 않는다. 오래된 action은 현재 관측과 상태를 반영하지 않으므로 폐기하거나 HOLD로 전환해야 한다.
5.9.5 최신 LeRobot 배포 backend
2026년 공식 LeRobot 배포 인터페이스는 동기 실행, local RTC(Real-Time Chunking), remote inference를 구분한다.
- Sync: control tick마다 policy call을 기다린다.
- Local RTC: rollout process의 background thread가 다음 chunk를 만들며 현재 trajectory와 이어지는 action을 준비한다.
- Remote inference: 별 process/host의 policy server와 통신하고 robot client가 bounded action buffer를 소비한다.
RTC의 execution_horizon, observation age, action/startup timeout, starvation grace는 실측 latency와 usable chunk horizon 안에서 정한다. queue가 비었다고 마지막 action을 무기한 유지하지 않는다. task instruction이 바뀌면 이전 instruction의 queued/in-flight action을 폐기하고 fresh observation으로 재계획한다. 최신 flag와 지원 checkpoint 계약은 Policy Deployment, Real-Time Chunking, Remote Inference를 따른다. 이전 async server/client tutorial의 actions_per_chunk, chunk_size_threshold와 최신 local RTC flag를 섞지 않는다.