Low Level (RL 정책) — Python 예제
소스: rbq_sdk/python/example/sport/rbq_low_level.py
rbq_low_level.cpp의 Python 포팅 버전.
IMU, 조이스틱, 관절 피드백 토픽을 구독하고, 관절 위치 레퍼런스를 발행하며, **학습된 보행 정책(ONNX)**을 10 Hz로 실행합니다.
동작 개요
백그라운드 스레드에서 단일 500 Hz 제어 루프 (2 ms 주기)가 실행됩니다. 키보드 기반 상태 머신이 활성 모드를 제어합니다:
| 상태 | 키 | 제어 루프 동작 |
|---|---|---|
| Idle | — | rt/rbq/ref/leg_joint/final을 구독하여 그대로 재발행 (pass-through) |
| Motion | x / z | 코사인 보간으로 관절을 ready 또는 ground 자세로 이동 |
| Control | c | ONNX 정책을 10 Hz로 실행 (5틱 중 1회), MotionRef_ 발행 |
사전 요구사항
rbq_sdk_py설치 완료 — Python SDK 개요 참조.- onnxruntime:
pip install onnxruntime info.json과policy.onnx가 있는 정책 디렉토리.- 로봇 스택이 실행 중(시뮬레이션 또는 하드웨어).
설치 및 실행
bash
cd RBQ/rbq_sdk/python
pip install -e .
pip install onnxruntimebash
cd RBQ/rbq_sdk/python/example/low_level
# networkInterface는 선택사항 (시뮬레이션에서는 루프백 기본값 사용)
python3 rbq_low_level.py -p <policyDir> [networkInterface]
# 예시
python3 rbq_low_level.py -p ../../../../rbq_simulator/rbq_gym/policy/rbq10/
python3 rbq_low_level.py -p ../../../../rbq_simulator/rbq_gym/policy/rbq10/ eth0C++ 버전과 달리
sudo가 필요하지 않습니다 — Python은 실시간 스레드를 사용하지 않습니다.
시뮬레이션으로 실행
RBQ/루트에서:bashbash scripts/sim.bash- RBQGUI: Connect → Auto Start Robot → Stance (
2). - 예제 실행 (시뮬레이션에서는 네트워크 인터페이스 생략 가능):bash
python3 rbq_low_level.py -p ../../../../rbq_simulator/rbq_gym/policy/rbq10/
키보드 제어
| 키 | 동작 |
|---|---|
q | 종료 |
z | ground 자세로 이동 (folding → ground, 약 4.8초) |
x | ready 자세로 이동 (ground → folding → ready, 약 2.8~5.6초) |
c | Walk / Control 모드 시작 (-p에서 정책 로드) |
키보드는 비정규 모드(non-canonical, no-echo)로 읽힘 — Enter 없이 즉시 반응.
정책 디렉토리
-p 디렉토리에 다음 파일이 있어야 합니다:
| 파일 | 역할 |
|---|---|
info.json | 정책 하이퍼파라미터 (run_name, policy_dt, action_scale, 강성/감쇠, 관측/행동 크기, 정규화 스케일, 기본 관절 각도, 명령 범위) |
policy.onnx | 학습 프레임워크에서 내보낸 ONNX 모델 |
지원 정책 이름 (info.json의 run_name):
| 이름 | 관측 벡터 | 비고 |
|---|---|---|
rbq10 | gyro, proj_grav, command, dof_pos, dof_vel, action | 단일 프레임 |
rbq10_trot | gyro, proj_grav, command, 4×dof_pos history (0,2,4,6), 4×dof_vel history, action×2, added_mass | 7프레임 히스토리 |
rbq10_trot_run | rbq10_trot과 동일 | 고속 런 변형 |
정책 이름은
info.json의config_info.run_name필드에서 가져옵니다.
DDS 토픽
| 방향 | 토픽 | 타입 | 설명 |
|---|---|---|---|
| 구독 | rt/rbq/cmd/joy/final | Joy_ | 조이스틱 축 (속도 명령) |
| 구독 | rt/rbq/info/imu | Imu_ | 각속도 + 방향 쿼터니언 |
| 구독 | rt/rbq/info/leg_joint | LegJointInfo_ | 관절 위치 및 속도 (12개) |
| 구독 | rt/rbq/ref/leg_joint/final | MotionRef_ | 최종 블렌딩된 레퍼런스 (Idle 상태용) |
| 발행 | rt/rbq/ref/leg_joint/owner_20 | MotionRef_ | PD 게인이 포함된 관절 위치 레퍼런스 |
| 발행 | rt/rbq/cmd/motion/joint_owner/_20 | JointOwnershipCmd_ | 12개 관절 소유권 요청 |
관절 순서
인덱스 0~11:
HR: HRR(0), HRP(1), HRK(2) → HL: HLR(3), HLP(4), HLK(5) → FR: FRR(6), FRP(7), FRK(8) → FL: FLR(9), FLP(10), FLK(11)
주요 구현 참고
- RT 스레드 없음:
time.sleep()으로 2 ms 주기를 유지합니다. C++ RT 스레드보다 타이밍 지터가 큽니다. 시뮬레이션과 테스트에는 적합하지만, 고동적 실로봇 운용에는 제약이 있을 수 있습니다. - 관측 사전 초기화:
SharedState의msg_imu,msg_leg,msg_joy는 기본값으로 초기화되어 있어, DDS 첫 샘플이 도착하기 전에도 정책이 즉시 실행됩니다. 아직 수신되지 않은 구독자가 있으면 0.5 Hz로 제한된 경고를 출력합니다. - 데시메이션: 정책 추론은 제어 루프 500 Hz의 5번째 틱마다 실행(10 Hz),
info.json의policy_dt와 일치. - 소유권: Motion 또는 Control 상태 진입 시
JointOwnershipCmd_를 한 번 발행하여 12개 관절 전체를 우선순위 20으로 요청. - 자세 감지:
go_to_motion_ready()는 4개의 hip-pitch 각도가 60°를 초과하면 로봇이 접힌 상태로 판단하여 folding 단계를 먼저 실행.
트러블슈팅
| 문제 | 가능한 원인 |
|---|---|
| 동작 없음 / 토픽 수신 없음 | 스택 미실행 또는 잘못된 네트워크 인터페이스 |
Policy, PolicyParams not loaded | -p 경로 오류, info.json / policy.onnx 누락 |
NaN or Inf in output data | 비정상 관측값; IMU 및 관절 토픽 확인 |
| 타이밍 경고 로그 | 시스템 부하 과다; 다른 프로세스 종료 |
