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>
5.9 KiB
03. 로봇/드라이버 시스템 구성
출처: README.md, xbox_motor_control.cpp (main 함수 상단 파라미터), 실측값
3.1 로봇 물리 제원
| 항목 | 값 | 비고 |
|---|---|---|
| 구동 방식 | 스키드 스티어(Skid-Steer) 4WD | 좌/우 각 2륜씩 기계적으로 독립 구동, 조향 없음 |
| 전폭 (Track Width, W) | 576.0 mm | 좌우 바퀴 중심 간 거리 |
| 전장 축간거리 (Wheelbase, L) | 368.4 mm | 전후 바퀴 중심 간 거리 |
| 휠 유효 반경 (R) | 131.517 mm | 버니어 실측값, 10.35인치 타이어 |
| 전면 범퍼 오프셋 | 45.0 mm | 휠 축 → 로봇 최전방 범퍼 |
| 로봇 전폭(차체) | 410 mm | 라이다 회피 폭 계산 기준 |
| 로봇 전장(차체) | 631 mm | |
| 로봇 전고 | 286 mm |
3.2 모터 & 드라이버 매핑
| 위치 | 모터 | 소속 드라이버 | Station ID | 시리얼 포트 | 드라이버 채널 |
|---|---|---|---|---|---|
| 전방 좌 (FL) | ZLLG80ASM250-4096-B V2.12 | 드라이버 #1 (전방) | 1 | /dev/ttyUSB0 |
Left |
| 전방 우 (FR) | ZLLG80ASM250-4096-B V2.12 | 드라이버 #1 (전방) | 1 | /dev/ttyUSB0 |
Right |
| 후방 좌 (RL) | ZLLG80ASM250-4096-B V2.12 | 드라이버 #2 (후방) | 2 | /dev/ttyUSB0 (동일 포트, 데이지체인) 또는 --port2 |
Left |
| 후방 우 (RR) | ZLLG80ASM250-4096-B V2.12 | 드라이버 #2 (후방) | 2 | 〃 | Right |
- 드라이버 2대는 동일 RS485 버스(같은 USB-RS485 포트)를 공유하는 것이 기본 동작이며,
Modbus 슬레이브 주소(1, 2)로 구분한다.
--port2를 지정하면 별도의 물리 포트를 사용하도록 전환 가능(sp2_ptr가&sp1대신&sp2를 가리키게 됨). --bcast/--broadcast옵션 사용 시 두 드라이버 모두 주소0(브로드캐스트)으로 동시에 명령을 받는다 — 이 경우 개별 피드백 조회/전류 조회는 생략된다(driver_rear_ptr = nullptr로 유지, 앞뒤 드라이버가 응답을 구분해 회신할 수 없기 때문).- 좌/우 부호가 반대인 이유:
MotorDriver::setRPMs(l_rpm, r_rpm)에 넘기는 지령에서target_fr = -v_r * rpm_per_ms,target_rr = -v_r * rpm_per_ms처럼 우측 바퀴는 항상 부호 반전해서 넘긴다. 좌/우 모터가 로봇 상에서 물리적으로 반대 방향으로 장착되어 있어 (양쪽 모터가 "전진"으로 회전해야 하는 U/V/W 위상이 거울 대칭) 이렇게 보정하지 않으면 우측 바퀴가 반대로 회전한다.
3.3 엔코더 해상도
- 모터 1회전당 16,384 ticks (4체배 카운팅 기준)
meters_per_tick = (2π × wheel_radius) / 16384- 주행거리(Odometry)는 4륜 엔코더 델타의 **중앙값(4개 중 중간 2개 평균)**으로 계산해,
웅덩이 등으로 한 바퀴가 들떠 헛도는 경우의 이상치를 자동으로 배제한다 (
dist_axle).dist_bumper = dist_axle + bumper_offset(전진 시)으로 범퍼 기준 거리도 함께 산출.
3.4 스키드 스티어 운동학
유효 선회 반경 계수
effective_w = sqrt(track_width² + wheelbase²) // 대각선 유효 폭
k_skid = (track_width + wheelbase² / track_width) / 2
k_skid는 순수 사각 스키드 스티어(회전축이 로봇 중심)보다 실제 마찰 중심을 반영해 보정한
계수로, 직진+커브 선회 시 좌/우 바퀴 속도 차를 계산하는 데 사용된다.
모드 1 — 직진/커브 선회 (is_spin_turn == false)
좌측 스틱 전후(ly)로 전진 속도 v_x = ly × max_v를 만들고, 좌측 스틱 좌우(lx)로 곡선 조향을
만든다. 저속에서 커브 반경이 스로틀과 무관하게 일정하도록, 각속도 omega는 현재 전진 속도
v_x에 비례하도록 계산된다(상수 max_v가 아님 — 저속에서 안쪽 바퀴가 역회전해버리는 버그를
막기 위한 수정):
omega += -lx * (abs(v_x) / (effective_w / 2))
v_l = v_x - omega * k_skid
v_r = v_x + omega * k_skid
target_fl = target_rl = v_l * rpm_per_ms
target_fr = target_rr = -v_r * rpm_per_ms // 우측 부호 반전
모드 2 — 제자리 회전 (is_spin_turn == true, ly==0 && rx!=0)
우측 스틱 좌우(rx)만으로 제자리 선회한다. 순수 제자리 회전(ICR이 로봇 중심)은 고마찰 노면에서
정지마찰이 급격히 파괴돼 바퀴가 긁히므로, **미세한 전진 성분(spin_arc_bias, 기본 12%)**을
섞어 ICR을 로봇 중심에서 살짝 벗어나게 해 스크럽 마찰을 줄인다:
omega = -rx * (max_spin_v / (effective_w / 2))
v_bias = abs(rx) * max_spin_v * spin_arc_bias
v_l = v_bias - omega * (effective_w / 2)
v_r = v_bias + omega * (effective_w / 2)
제자리 회전 진입 조건은 ly == 0.0f의 완전 일치 비교다. applyDeadzone()이 데드존
이하 입력을 정확히 0.0f로 반환하기 때문에 안전하며, 부동소수점 근사 오차로 인한 오탐을
막기 위해 별도 임계값을 두지 않고 정확히 이 특성에 의존한다.
라이다 자동 회피 조향 (측면 회피 시, 조이스틱 좌우 입력이 없을 때)
v_l = v_x - omega * k_skid
v_r = v_x + omega * k_skid
(제자리 회전이 아니면서 lx==rx==0이고 omega!=0인 경우 — 04-software-control.md
의 라이다 회피 절 참고)
3.5 속도 → 드라이버 RPM 지령 변환
rpm_per_ms = 60 / (2π × wheel_radius) // m/s → RPM 변환 계수
계산된 target_*(RPM)는 곧바로 드라이버에 보내지 않고, 저크 제한(Jerk-Limited) S-curve
프로파일(jerkLimitedStep())을 거쳐 cmd_*로 서서히 수렴한 뒤 setRPMs()로 전달된다.
소프트웨어 측 가감속/저크 프로파일은 드라이버 자체의 가감속 레지스터(0x2080~0x2083,
150ms)보다 상위 레벨에서 한 번 더 부드럽게 다듬는 이중 구조다. 상세는
04-software-control.md 참고.