Files
fori_zltech_motor_test/doc/03-system-architecture.md
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

5.9 KiB
Raw Permalink Blame History

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 참고.