Files
fori_zltech_motor_test/QnA/a1.md
T
Dongubak 2f21d86193 Add ZLAC8015D driver docs, IMU integration plan, and reference resources
Documents the ZLAC8015D V4 dual-channel driver (hardware spec, RS485
Modbus register map, 4WD skid-steer system architecture, the
xbox_motor_control.cpp control loop, and error/troubleshooting) under
doc/, plus a phased plan for adding IMU-based heading/slip feedback
(doc/06) informed by Clearpath Husky's sensor fusion stack and
skid-steer ICR literature. QnA/ records the Q&A that refined that plan.
Also adds the underlying manual PDFs and reference links under
resource/ that the docs cite.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-16 00:17:24 +09:00

188 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## A (q1.md에 대한 답변)
`doc/06-imu-integration-plan.md`에 대한 4가지 질문에 순서대로 답한다. 결론을 먼저 요약하면:
**개루프(조이스틱)와 폐루프(IMU 트림)는 상충하지 않으며 실무에서도 계층 구조로 함께 쓰인다.
ICR은 실제로 동적이며 9축 IMU로 온라인 추정이 가능하다. 헤딩 홀드는 상대 헤딩 기준 + 최소한의
필터링으로 충분하다. HWT905는 RS485/Modbus를 지원해 기존 통신 스택 재사용이 가능하다.**
---
### Q1. 조이스틱 폐루프 제어가 실무에서 실제로 쓰이는가?
**결론: 쓰인다. 다만 사용자가 걱정하는 "조이스틱 값이 바뀌면 폐루프 계산을 처음부터 다시 해야
한다"는 문제는 애초에 발생하지 않는다.** 그 걱정 자체가 폐루프 제어에 대한 흔한 오해를 짚고
있어서, 왜 문제가 안 되는지부터 설명한다.
#### 왜 "재계산 문제"가 없는가
폐루프 제어의 기본 형태는 다음과 같다.
```
e(t) = r(t) y(t) // r(t): 기준값(레퍼런스), y(t): 센서 측정값
u(t) = Controller(e(t)) // 그 순간의 오차만 보고 그 순간의 보정량을 계산
```
여기서 `r(t)`(조이스틱이 매 순간 주는 목표값)가 틱마다 바뀌는 것은 폐루프 제어의 정상적인
동작 방식이지, 예외 상황이 아니다. 제어기는 "이전 계산이 끝날 때까지 기다렸다가 다음 값을
반영"하는 게 아니라, **매 사이클(본 프로젝트는 100Hz=10ms)마다 그 순간의 `r(t)``y(t)`만으로
그 순간의 보정량 하나를 계산**한다. 지금 이미 코드에 있는 `jerkLimitedStep()`도 정확히 이 구조다
`target_*`(조이스틱에서 매 틱 갱신되는 레퍼런스)가 바뀌어도 다음 틱에서 그냥 새 `target_*`
기준으로 다시 한 스텝 계산할 뿐, "이전 목표를 향한 계산이 안 끝났으니 못 바꾼다"는 일이 없다.
헤딩 홀드도 동일한 구조로 넣을 수 있다.
#### 이미 이 프로젝트에도 폐루프가 존재한다
"조이스틱 제어 = 개루프"라는 인식은 절반만 맞다. 계층을 나눠보면:
| 계층 | 신호 흐름 | 개/폐루프 |
| :--- | :--- | :-: |
| 상위 (조이스틱 → 목표 RPM) | `ly/lx/rx` → 스키드 스티어 킨매틱스 → `target_fl/fr/rl/rr` | **개루프** (피드포워드) |
| 중위 (목표 RPM → 지령 RPM) | 저크 제한 S-curve (`jerkLimitedStep`) | 개루프 프로파일 생성 (폐루프 아님, 단 매 틱 최신 목표 반영) |
| **하위 (지령 RPM → 실제 RPM)** | **드라이버 내장 Velocity Loop** (`0x203C`/`0x203D`/`0x203E` L, `0x206C`/`0x206D`/`0x206E` R — Kp/Ki/Kf) | **이미 폐루프.** 부하가 걸려도 드라이버가 실제 RPM을 지령 RPM에 맞추려 함 |
즉 지금도 "조이스틱 값 → 목표 속도"까지는 개루프지만, "목표 속도 → 실제 바퀴 속도"는 이미
드라이버가 폐루프로 하고 있다. IMU 헤딩 홀드(계획서 Phase 3)는 이 구조에 **한 계층을 더
얹는 것**뿐이다: "조향 입력이 중립일 때, 목표 요레이트(=0)와 실측 요레이트(IMU)의 오차를 보고
좌/우 목표 RPM에 작은 트림을 더한다." 조이스틱이 다시 움직이면(조향 입력 재개) 그 즉시 헤딩
락을 풀고 트림을 0으로 되돌리면 되므로, "조이스틱 값 변경 시 재계산" 문제는 설계상 발생하지
않는다.
#### 실무 사례 (동일 패턴)
* **자동차 ESC/TCS(전자식 주행안정장치)**: 운전자의 스티어링·가속페달이 항상 최우선 레퍼런스지만,
요레이트 센서가 실측한 값이 스티어링 각도로부터 기대되는 값과 어긋나면 개별 바퀴 브레이크/토크를
트림한다. 운전자가 스티어링을 계속 바꿔도 문제없이 동작 — 매 사이클 그 순간의 편차만 본다.
* **쿼드콥터**: 스틱은 각속도/자세에 대한 레퍼런스이고, 내부 자세제어 루프가 IMU로 안정화한다.
스틱을 중립으로 놓으면 자세/포지션 홀드로 전환되어 바람 등 외란을 자동 보정 — Phase 3와 정확히
동일한 "중립 시에만 홀드" 패턴.
* **선박 오토파일럿**: 조타핸들이 중립일 때만 자이로컴퍼스 기준 헤딩홀드가 개입하고, 조타를
움직이면 즉시 새 헤딩으로 재설정된다.
**요약**: 실무의 표준 패턴은 "조이스틱 = 상위 레퍼런스(운전자 의도, 매 틱 갱신 가능) + 하위
폐루프(그 레퍼런스를 추종·안정화)"의 계층 구조다. 계획서 Phase 3가 제안하는 헤딩 홀드도 이
패턴을 그대로 따른다.
---
### Q2. ICR이 동적이라면, IMU로 이를 감지해 더 고차원의 제어가 가능한가?
**결론: 가능하다. 그리고 지적한 대로 현재 로직은 "동적으로 변하는 현상을 정적 스칼라로 땜빵"한
것이 맞다.**
#### 현재 로직이 "땜빵"인 이유 (재확인)
`k_skid`, `effective_w`는 로봇 형상(트랙폭, 축거)만으로 계산된 기하학적 근사치이고,
`spin_arc_bias=0.12`는 실측 없이 경험으로 넣은 상수다. 이 값들은 지면 마찰계수, 무게중심,
경사, 타이어 트레드 마모, 속도에 따라 실제로는 계속 바뀌는 "유효 ICR"을 대표할 수 없다
— 특정 노면/속도 조건에서 튜닝된 값일 뿐이다.
#### 9축 IMU가 추가하는 정보 차원
| IMU 축 | 얻는 정보 | 현재(전류+엔코더)로는 불가능한 이유 |
| :--- | :--- | :--- |
| 자이로 요레이트 | 로봇이 **실제로** 얼마나 회전하고 있는가 (슬립 무관) | 전류는 부하/토크 정보, 엔코더는 개별 바퀴 회전량 정보일 뿐 — 차체가 실제로 얼마나 돌았는지는 아무도 안 알려준다 |
| 가속도계 (중력보정 후) | 급조향/급가감속 시 차체가 실제로 그만큼 가속했는가 | 저크 리미터가 만드는 "기대 가속도"와 비교해 "명령은 갔는데 차체가 안 따라옴" 상태(전신 슬립)를 검출 가능 |
| Roll/Pitch(경사각) | 현재 지형이 경사면인지 | 경사에서는 좌우 바퀴 접지압이 비대칭이 되어 ICR이 더 크게 틀어짐 — 지금은 이 정보 자체가 전무 |
| 지자기 | 절대 방위 참조 (제한적) | 다만 차체가 모터/드라이버/배터리 등 금속 덩어리라 지자기 왜곡이 클 가능성이 높음 — 절대 헤딩보다는 참고용으로만 신중히 사용 권장 |
#### "정적 캘리브레이션"보다 한 단계 더 — 온라인 ICR 추정
계획서 Phase 5(§6.4)는 원래 "몇 차례 실측 후 한 번 피팅해서 상수를 교체"하는 **정적**
캘리브레이션으로 설계했다. 하지만 지적한 대로 ICR이 지형에 따라 계속 바뀐다면, 매 틱
```
effective_ICR_gain = 실측_요레이트(IMU) / 지령_차동속도
```
를 계속 갱신하는 **온라인 추정**(Pentzer 2014가 제안한 방식)이 이론적으로는 더 맞는 방향이다.
다만 이건 Phase 5를 정적 캘리브레이션 → 상시 온라인 추정으로 확장하는 것이므로, 구현 난이도와
실외 검증 부담이 커진다. 이번 답변을 반영해 계획서 §6.4 Phase 5에 "1차: 정적 캘리브레이션으로
먼저 검증 → 2차: 온라인 추정으로 확장 가능"이라는 단계를 추가해 두었다(아래 "계획서 반영"
참고).
#### 우선순위: 조이스틱 제어가 먼저라는 원칙과의 정합성
이 답변에서 제안하는 내용은 계획서의 Phase 순서를 바꾸지 않는다. Phase 1~2(§6.4)는 IMU 값을
"관측/로깅"만 할 뿐 제어에 전혀 개입하지 않으므로, 조이스틱 제어 자체의 완성도에는 영향을 주지
않는다. ICR 온라인 추정 같은 고차원 활용은 Phase 5 이후, 즉 조이스틱 경로가 충분히 검증된
다음에야 의미가 있는 단계로 이미 순서가 잡혀 있다.
---
### Q3. 헤딩 기준을 IMU로 얻어 직진 편향 보정이 가능한가? 필터는?
**결론: 맞다. 그리고 이 용도에서는 "정밀한 절대 헤딩"이 아니라 "짧은 구간 동안의 상대 헤딩"만
있으면 되기 때문에, 필터링 요구 수준이 생각보다 무겁지 않다.**
#### 왜 절대 헤딩이 필요 없는가
Phase 3(§6.4)의 헤딩 홀드는 "조향 입력이 중립인 동안 로봇이 옆으로 틀어지지 않게" 하는 용도다.
조향 입력이 다시 들어오면(사용자가 스틱을 움직이면) 헤딩 락을 풀고, 다시 중립이 되는 시점에
**그 순간의 방향을 새 기준으로 재설정(reset)**하면 된다. 즉 각 "직진 구간"은 보통 수 초~수십 초
단위이므로, 자이로 바이어스 드리프트가 누적될 시간 자체가 짧아 실사용상 큰 문제가 되지 않는다.
(장기 절대 헤딩이 필요해지는 건 계획서 Phase 6의 자율주행/맵핑 단계부터다.)
#### 그래도 필요한 최소한의 처리
1. **정적 바이어스 캘리브레이션**: 전원 인가 직후 정지 상태에서 수 초간 자이로 값을 평균 내
영점(zero-rate offset)을 구해 빼준다. 이거 없이는 정지 중에도 헤딩이 서서히 흘러간다.
2. **노이즈 필터링**: 실외 오프로드 특성상 진동이 크다. 저역통과 또는 이동평균 정도로 고주파
진동 성분을 제거해야 트림 제어기가 노이즈에 반응해 떨지 않는다.
3. **HWT905류 온보드 AHRS 모듈을 쓰면 위 부담이 상당 부분 줄어든다**: 이 모듈은 가속도+자이로
+지자기를 내부적으로 칼만필터 등으로 융합해 이미 안정화된 roll/pitch/yaw를 직접 출력한다.
순수 MEMS 칩(raw 자이로 값만 주는 IC)을 쓰는 것보다 애플리케이션 쪽 필터링 구현 부담이
훨씬 적다 — Q4에서 이어서 설명.
---
### Q4. IMU 하드웨어: HWT905 확정
WitMotion 공식 자료 기준으로 확인한 HWT905-RS485 스펙 (정식 PDF 매뉴얼은 이미지 기반이라
텍스트 자동 추출이 안 돼, 아래는 제조사 웹페이지 기준 요약이다 — 레지스터 맵 등 세부 사항은
§실행 전 확인 필요 참고):
| 항목 | 내용 |
| :--- | :--- |
| 측정 축 | 9축 — 가속도 3축 + 자이로 3축 + 지자기 3축, 내장 자세융합 알고리즘으로 roll/pitch/yaw 직접 출력 |
| 통신 | RS485, **Modbus 프로토콜 지원**(레지스터 리스트 기반) |
| 보드레이트 | 기본 9600bps, 2400~921600bps 가변 |
| 출력 레이트 | 최대 200Hz |
| 정확도 | 제조사 공식 스펙 "0.05°" (동적/정적 조건은 정식 PDF 확보 후 재확인 필요) |
| 케이스 | 55×36.8×24mm 알루미늄, **IP67 방수/방진** |
| 케이블 | RS485 최대 30m |
#### 이 프로젝트에 잘 맞는 이유
1. **RS485 + Modbus 프로토콜**`xbox_motor_control.cpp``SerialPort` 클래스(Modbus RTU,
CRC16, `readReg`/`writeReg`/`readRegs` 패턴)를 상당 부분 재사용할 수 있다. IMU만을 위한
완전히 새로운 통신 스택을 만들 필요가 없다. (단, ZLAC8015D 2대가 이미 쓰고 있는 버스에
같이 물릴지, 별도 물리 포트로 분리할지는 §실행 전 확인 필요에서 결정해야 한다 — 100Hz
루프에서 통신 3개 슬레이브를 한 버스로 돌리면 틱당 통신 시간이 늘어날 수 있다.)
2. **IP67 방수/방진** — 실외 로봇이라는 조건에 부합.
3. **온보드 AHRS 융합** — Q3에서 설명한 필터링 부담을 하드웨어가 상당 부분 대신 처리해준다.
저가 MEMS 칩 대비 확실한 이점.
#### 실행 전 확인 필요 (아직 확정 못한 것)
이번 조사에서 확보한 HWT905 정식 매뉴얼 PDF는 이미지 스캔본이라 텍스트 추출이 되지 않아,
**정확한 레지스터 주소(각속도/각도/가속도/지자기 레지스터, 출력레이트 설정 레지스터, 슬레이브
주소 설정 방법 등)는 이번 문서에 포함하지 못했다.** ZLAC8015D 때와 동일한 방식으로 진행하려면:
1. HWT905 정식 매뉴얼(텍스트 검색 가능한 PDF)을 `resource/`에 추가.
2. `doc/07-imu-hwt905-spec.md`(가칭)로 레지스터 맵을 ZLAC8015D 문서와 동일한 정밀도로 문서화.
3. 그 다음에야 Phase 1(하드웨어 연동) 코드 작업 착수.
---
## 계획서(`doc/06-imu-integration-plan.md`) 반영 사항
이 답변 내용을 반영해 계획서를 다음과 같이 갱신했다:
* §6.7 "결정이 필요한 사항" 중 **IMU 하드웨어 항목을 HWT905로 확정** 표시.
* Phase 5에 "정적 캘리브레이션 → 온라인 ICR 추정으로 확장 가능" 단계 구분을 추가.
* Phase 1 앞에 "IMU 정식 매뉴얼 확보 및 레지스터 맵 문서화"를 선행 작업으로 명시.
남은 결정 사항: **IMU를 ZLAC8015D와 같은 RS485 버스에 물릴지, 별도 포트로 분리할지** — 이건
실측(버스 하나에 3개 슬레이브 얹었을 때 100Hz 루프의 `comm_ms` 여유가 있는지) 후 결정하는 것을
제안한다.