Add LIDAR/SLAM plan and improvements report docs
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,207 @@
|
|||||||
|
# 07. Livox Mid-360S 기반 LiDAR SLAM 도입 계획 (Phase 6, 실행 전 검토용)
|
||||||
|
|
||||||
|
> **이 문서는 계획안이다. 코드는 아직 수정하지 않았다.** [06-imu-integration-plan.md](06-imu-integration-plan.md)
|
||||||
|
> §Phase 6("장기, 선택")에서 예고된 자율주행 확장을 구체화한 문서로, 아래 내용을 검토하고 방향에
|
||||||
|
> 동의하면 그때 실제 작업(ROS2 설치, 패키지 빌드, URDF/ros2_control 작성, 코드 통합)을 시작한다.
|
||||||
|
|
||||||
|
## 7.1 현재 상태 (코드 근거)
|
||||||
|
|
||||||
|
로봇에는 Livox Mid-360S가 이미 장착되어 있고 `xbox_motor_control.cpp`가 Livox SDK2
|
||||||
|
(`livox_lidar_api.h`)로 직접 연동하고 있지만, 이건 **반응형 장애물 회피 전용**이지 SLAM이 아니다.
|
||||||
|
|
||||||
|
`LidarObstacleDetector::handlePointCloud()`(`xbox_motor_control.cpp:532`)는 패킷으로 들어오는
|
||||||
|
포인트를 하나씩 받아 전방/후방/좌/우 4개 구역의 **최소 거리 스칼라값**으로 즉시 축약하고, 원본
|
||||||
|
포인트는 저장하지 않은 채 버린다. 즉:
|
||||||
|
|
||||||
|
| 항목 | 현재 | SLAM에 필요 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| 포인트클라우드 | 수신 즉시 4개 거리값으로 축약 후 폐기 | 누적·저장 필요 |
|
||||||
|
| 자세 추정(6-DOF) | 없음 (단순 거리 임계값 반응) | 매 스캔마다 위치·자세 추정 |
|
||||||
|
| 지도 | 없음 | 포인트클라우드 지도 생성/관리 |
|
||||||
|
| 루프 클로저 | 해당 없음 | 누적 드리프트 보정 필요 |
|
||||||
|
| 로봇 모델(TF) | 없음 — ROS 개념 자체가 없는 단일 C++ 프로그램이라 `base_link`↔바퀴/센서 간 좌표 관계가 코드 상수로만 흩어져 있음 | URDF로 명시해 `robot_state_publisher`가 TF 트리 발행 — Nav2 costmap 풋프린트, RViz 정합, 센서 외부 파라미터(extrinsics)에 모두 필요 |
|
||||||
|
| 속도명령 실행 인터페이스 | `setRPMs()` 직접 호출(자체 프로토콜) | Nav2가 내는 `/cmd_vel`을 표준화된 방식으로 받아 실제 바퀴 명령으로 변환하는 레이어 필요 |
|
||||||
|
|
||||||
|
## 7.2 Mid-360S는 SLAM에 유리한 센서
|
||||||
|
|
||||||
|
Mid-360S는 논-리피티티브(non-repetitive) 스캔 방식 솔리드스테이트 라이다로, Livox가 이 시리즈
|
||||||
|
(Mid-360/Avia 등) 전용으로 **FAST-LIO2**, **Point-LIO** 같은 LiDAR-Inertial Odometry(LIO) SLAM
|
||||||
|
패키지를 공식 지원·공개하고 있다. 지금 쓰는 SDK2도 이미 이 생태계의 표준이라 하드웨어/펌웨어
|
||||||
|
호환성 문제는 적을 것으로 예상된다.
|
||||||
|
|
||||||
|
**주의**: Mid-360S 내부에는 **자체 IMU가 내장**되어 있고 LIO 패키지들은 보통 이 내장
|
||||||
|
IMU(라이다와 시간 동기화됨)를 쓴다. [06번 문서](06-imu-integration-plan.md)에서 연동한 외부
|
||||||
|
WitMotion HWT905와는 별개의 센서이니 혼동하지 않는다.
|
||||||
|
|
||||||
|
## 7.3 권장 스택
|
||||||
|
|
||||||
|
* **ROS2** + **livox_ros_driver2**(Livox 공식 드라이버, Mid-360S 정식 지원)
|
||||||
|
* **FAST-LIO2** 또는 **Point-LIO** (Point-LIO가 상대적으로 최신/고속)
|
||||||
|
* **URDF/xacro** — 휠베이스·트랙폭·휠 반경 등 차체 치수와 Mid-360S/WitMotion IMU 마운트 위치를
|
||||||
|
정의해 `robot_state_publisher`로 TF 트리를 발행. Nav2 costmap 풋프린트, RViz 시각화, 센서
|
||||||
|
외부 파라미터(extrinsics) 계산 등 이후 모든 단계의 기반이 된다.
|
||||||
|
* **ros2_control** — Nav2가 내는 `/cmd_vel`을 이 로봇의 실제 4바퀴 RPM으로 바꾸는 실행 레이어를
|
||||||
|
ROS2 표준 프레임워크 안에서 구현(자세한 내용은 §7.4.4). 스캔매칭·루프클로저·지도관리를 직접
|
||||||
|
C++로 새로 구현하는 것과 달리, 이 실행 레이어는 이 로봇 고유의 하드웨어/킨매틱스 지식이 필요해
|
||||||
|
검증된 오픈소스로 대체할 수 없는 부분이다 — `xbox_motor_control.cpp`의 기존 로직을
|
||||||
|
ros2_control 플러그인 형태로 옮기는 작업이 된다.
|
||||||
|
* 스캔매칭·루프클로저·지도관리를 직접 C++로 새로 구현하는 것은 권장하지 않는다 — 검증된
|
||||||
|
오픈소스 대비 얻는 이득이 적고, [06번 문서](06-imu-integration-plan.md) Phase 1~5a와는
|
||||||
|
작업 성격이 다른(이미 성숙한 알고리즘을 재발명하는) 리스크가 크다.
|
||||||
|
|
||||||
|
## 7.4 통합 아키텍처 — 결정이 필요한 지점
|
||||||
|
|
||||||
|
`xbox_motor_control.cpp`는 ROS 없이 라이다 SDK를 직접 붙잡는 단일 C++ 프로그램인데, SLAM
|
||||||
|
스택은 보통 ROS2 기반이라 아래를 먼저 결정해야 한다.
|
||||||
|
|
||||||
|
### 7.4.1 라이다 동시 접근 가능 여부
|
||||||
|
|
||||||
|
Livox SDK2는 라이다가 UDP로 데이터를 뿌리는 방식이라, SDK 레벨에서 멀티 클라이언트가 되는지
|
||||||
|
먼저 확인이 필요하다. 안 되면 SLAM 프로그램만 라이다를 잡고, `xbox_motor_control.cpp`의
|
||||||
|
반응형 회피는 SLAM 노드가 만드는 로컬 코스트맵/장애물 토픽을 구독하는 구조로 바꿔야 한다.
|
||||||
|
|
||||||
|
### 7.4.2 통합 방식 두 가지
|
||||||
|
|
||||||
|
| 방식 | 설명 | 트레이드오프 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **(A) Nav2로 완전 이관** | ROS2 Navigation Stack이 경로계획+속도명령(`/cmd_vel`)을 전담. [06번 문서](06-imu-integration-plan.md) §6.5의 Husky 대응표가 가리키는 정석 구조. | 아래 §7.4.3 참고 — 전부 버려지는 게 아니라 레이어가 나뉜다. `/cmd_vel`→바퀴 RPM 실행 레이어는 §7.4.4의 URDF+ros2_control로 표준화해서 구현 |
|
||||||
|
| **(B) 얇은 브릿지** | SLAM/Nav2는 지도 생성 + 웨이포인트 좌표만 내주고, `xbox_motor_control.cpp`는 지금 구조(RC + 자체 제어루프) 그대로 두고 웨이포인트를 받아 목표 방향으로 이동하는 자율주행 모드를 추가. | 웨이포인트↔RC급 명령 변환 브릿지 코드를 직접 작성해야 함. ROS2 표준 실행 레이어(ros2_control)를 쓰지 않으므로 URDF도 TF/RViz 정합 용도 외에는 필수가 아님 |
|
||||||
|
|
||||||
|
### 7.4.3 (A)를 선택해도 지금까지의 제어 로직이 사라지지 않는 이유
|
||||||
|
|
||||||
|
Nav2가 대체하는 건 "지도 위에서 어디로 가야 하는지 결정하는" **상위 계획 레이어**(경로 계획,
|
||||||
|
웨이포인트 추종, 전역 장애물 회피 → `/cmd_vel` 생성)뿐이다. `/cmd_vel`(목표 v_x, omega)을 **이
|
||||||
|
로봇의 특정 하드웨어에 맞는 실제 4바퀴 RPM으로 바꾸는 실행 레이어**는 Nav2가 전혀 모르는
|
||||||
|
영역이라 (A)를 선택해도 계속 필요하다:
|
||||||
|
|
||||||
|
* **Phase 5a(k_skid/effective_w 캘리브레이션)** — Nav2는 "이만큼 회전해라"만 던질 뿐, 이 로봇이
|
||||||
|
스킷스티어라 회전 시 차동을 얼마나 더 세게 걸어야 하는지는 모른다. 이 변환은 계속 우리 코드의
|
||||||
|
몫이다.
|
||||||
|
* **저크 제한 감속 / 급가속 시 반전 방지** — 백EMF 보호, 급정지 시 바퀴 튀는 걸 막는 액추에이터
|
||||||
|
레벨 안전은 Nav2 담당이 아니다. 계속 필요.
|
||||||
|
* **Phase 4(전신 슬립 감지), 걸림/들뜸 진단** — 전류·엔코더·IMU로 보는 바퀴 트랙션 이상은
|
||||||
|
라이다 기반 회피(Nav2 담당)와 완전히 다른 종류의 안전장치라 계속 필요.
|
||||||
|
* **Phase 2(휠+IMU 융합 오도메트리)** — 오히려 Nav2/`robot_localization`이 정확히 이런 형태의
|
||||||
|
오도메트리 토픽을 입력으로 기대하므로, 없어지는 게 아니라 더 핵심적인 역할을 하게 된다.
|
||||||
|
|
||||||
|
**실제로 역할이 애매해지는 건 Phase 3(헤딩홀드)** 정도다 — RC 수동조종 중 직진 편향 보정용인데,
|
||||||
|
자율주행 중에는 Nav2의 로컬 플래너가 그 역할을 대신한다. 다만 RC 수동조종 모드를 비상/테스트용
|
||||||
|
폴백으로 남겨둔다면(대부분의 실제 로봇이 그렇게 한다) 그 모드에서는 계속 쓰인다.
|
||||||
|
|
||||||
|
정리하면 (A)를 선택해도 **RC 수동조종 관련 부분(CRSF 파싱, 헤딩홀드의 RC 트리거 조건)만
|
||||||
|
자율주행 중엔 쓰이지 않는 정도**지, 킨매틱스/안전진단/오도메트리는 전부 계속 쓰인다.
|
||||||
|
|
||||||
|
## 7.4.4 URDF + ros2_control로 실행 레이어 구현
|
||||||
|
|
||||||
|
§7.4.3에서 정리한 "Nav2가 몰라도 계속 필요한" 로직들(Phase 5a 킨매틱스 캘리브레이션, 저크 제한
|
||||||
|
S-curve, 전신 슬립 감지, 온도 모니터링)은 없어지지 않되, **`xbox_motor_control.cpp`라는 독립
|
||||||
|
C++ 프로그램에서 ROS2 표준 실행 레이어인 ros2_control로 옮겨 담는** 재구성이 필요하다.
|
||||||
|
|
||||||
|
* **URDF**: 휠베이스·트랙폭·휠 반경 등 실측 치수와 Mid-360S/WitMotion IMU 마운트 위치를 담아
|
||||||
|
`robot_state_publisher`가 TF 트리(`base_link` → 4개 바퀴 → 라이다/IMU)를 발행하게 한다. 이
|
||||||
|
URDF 안에 `<ros2_control>` 태그로 하드웨어 인터페이스를 선언하는 것이 표준 패턴이므로, URDF
|
||||||
|
작성과 ros2_control 플러그인 작성은 사실상 한 세트로 진행한다.
|
||||||
|
* **ros2_control 하드웨어 인터페이스**: `hardware_interface::SystemInterface`를 구현하는
|
||||||
|
플러그인을 새로 작성해, 기존 `xbox_motor_control.cpp`가 갖고 있던 다음 로직을 그대로 이식한다
|
||||||
|
— ZLAC8015D Modbus 통신, [06번 문서](06-imu-integration-plan.md) Phase 5a의 `k_skid`/
|
||||||
|
`effective_w` 실측 캘리브레이션, 저크 제한 감속, 전신 슬립 감지, 모터/드라이버 온도 모니터링.
|
||||||
|
즉 **하드웨어와 직접 통신하는 코드는 거의 그대로 재사용**하고, 그걸 감싸는 인터페이스만
|
||||||
|
ros2_control 표준(`read()`/`write()` 사이클)에 맞춘다.
|
||||||
|
* **컨트롤러 선택**: 이 로봇은 4륜 스킷스티어라 ROS2 표준 컨트롤러 중 정확히 맞는 것이 없다.
|
||||||
|
좌우 바퀴 쌍을 각각 하나의 가상 바퀴로 묶어 `diff_drive_controller`를 쓰는 방법과, 스킷스티어
|
||||||
|
전용 커스텀 컨트롤러를 작성하는 방법 중 하나를 골라야 한다 — `diff_drive_controller` 재사용
|
||||||
|
쪽이 구현 비용은 적지만, `k_skid`/`effective_w` 보정이 컨트롤러 레벨(바퀴 속도 변환)과
|
||||||
|
하드웨어 인터페이스 레벨(Phase 5a 캘리브레이션 자체) 중 어디서 적용돼야 하는지 먼저 정리해야
|
||||||
|
이중 보정 같은 실수를 피할 수 있다.
|
||||||
|
* **RC 수동조종과의 공존**: CRSF 파싱과 헤딩홀드는 §7.4.3에서 확인했듯 계속 필요하므로, 이
|
||||||
|
부분은 ros2_control 밖(별도 ROS2 노드 또는 하드웨어 인터페이스 내 폴백 모드)에 남기고, RC
|
||||||
|
브레이크(CH5)가 눌리면 ros2_control 경유 명령보다 우선하도록 안전 우선순위를 명확히 설계한다.
|
||||||
|
* 이 작업은 Phase 4(§7.5)에서 (A)를 선택했을 때 실제로 손대는 코드이며, 아직 SLAM/Nav2 경로
|
||||||
|
판단이 검증되지 않은 Phase 1~3 단계에서는 시작하지 않는다 — §7.5의 "먼저 관측으로 검증 후
|
||||||
|
개입" 원칙을 여기에도 그대로 적용한다.
|
||||||
|
|
||||||
|
## 7.5 단계적 진행 순서 (Phase 별)
|
||||||
|
|
||||||
|
[06번 문서](06-imu-integration-plan.md)와 같은 원칙을 따른다 — **먼저 순수 관측으로 검증하고,
|
||||||
|
주행 제어에는 그 검증이 끝난 뒤에만 개입한다.** 각 Phase는 이전 Phase의 검증 게이트를 통과해야
|
||||||
|
다음으로 넘어간다.
|
||||||
|
|
||||||
|
### Phase 1 — 인프라 확인 (관측 없음, 설치/연결 확인만)
|
||||||
|
|
||||||
|
* Livox SDK2가 멀티 클라이언트를 지원하는지 확인(§7.4.1) — 지원 안 되면 `xbox_motor_control.cpp`의
|
||||||
|
기존 반응형 회피(`LidarObstacleDetector`)와 라이다를 동시에 잡을 수 없다는 뜻이므로, 이후
|
||||||
|
아키텍처(§7.4.2의 A/B 선택, 회피 로직 재구성 여부)에 직접 영향을 준다. **가장 먼저 확인해야
|
||||||
|
나머지 계획이 헛수고가 되지 않는다.**
|
||||||
|
* ROS2 설치 + `livox_ros_driver2` 빌드, Mid-360S 데이터가 ROS2 토픽(`/livox/lidar`,
|
||||||
|
`/livox/imu`)으로 정상 발행되는지 확인. 아직 SLAM 패키지는 안 돌린다 — 순수 드라이버
|
||||||
|
연결 확인 단계.
|
||||||
|
* **URDF(xacro) 작성**: 휠베이스·트랙폭·휠 반경 등 실측 치수와 Mid-360S/WitMotion IMU 마운트
|
||||||
|
위치를 반영해 `robot_state_publisher`가 TF 트리(`base_link` → 바퀴/센서)를 발행하도록 한다.
|
||||||
|
아직 ros2_control 태그는 비워두거나 mock 하드웨어로 둔다 — 이 단계에서는 모터 제어와
|
||||||
|
전혀 연결하지 않는다. §7.4.4 참고.
|
||||||
|
* **게이트**: `ros2 topic hz`/`rviz2`로 포인트클라우드가 끊김 없이 정상 주파수로 들어오고,
|
||||||
|
내장 IMU 토픽도 같이 나오는 것을 확인해야 다음 단계로 넘어간다. RViz에서 라이다 포인트가
|
||||||
|
URDF 로봇 모델과 정렬되어 보이는지(TF 트리 정합성)도 함께 확인한다.
|
||||||
|
|
||||||
|
### Phase 2 — 실내/정적 SLAM 검증 (주행 제어 완전히 미개입)
|
||||||
|
|
||||||
|
* FAST-LIO2 또는 Point-LIO를 빌드해, **로봇을 손으로 들거나 실내에서 천천히 밀며** 지도가
|
||||||
|
쌓이는지 확인한다. 아직 로봇의 모터 제어와는 전혀 연결하지 않는다 — 라이다+SLAM 노드만
|
||||||
|
독립적으로 돌리는 단계.
|
||||||
|
* 확인 항목: 지도 품질(벽/기둥 등 기준점이 흐트러지지 않는지), 제자리로 돌아왔을 때 루프
|
||||||
|
클로저가 잘 닫히는지, 실시간 처리 속도가 로봇 탑재 컴퓨팅 자원으로 감당되는지.
|
||||||
|
* **게이트**: 통제된 실내 환경에서 지도/루프클로저가 안정적으로 나와야 다음 단계로 넘어간다.
|
||||||
|
여기서 불안정하면 그 상태로 야외에 나가봐야 결과가 더 나빠질 뿐이다.
|
||||||
|
|
||||||
|
### Phase 3 — 로봇 탑재 야외 검증 (여전히 주행 제어 미개입, RC 수동조종과 병행 관측)
|
||||||
|
|
||||||
|
* 실제 로봇에 SLAM 노드를 올리고, **RC로 수동 조종하며** 지금까지 테스트해온 실야외 노면(파인
|
||||||
|
보도블럭/아스팔트/잔디)에서 지도/자세추정이 안정적인지 확인한다. 실내 벤치마크보다 훨씬
|
||||||
|
가혹한 환경(직사광선 반사, 개활지라 루프클로저용 기준점이 적음, 진동)이라 별도 검증이
|
||||||
|
필요하다.
|
||||||
|
* [06번 문서](06-imu-integration-plan.md) Phase 2에서 만든 **휠+IMU 융합 오도메트리(x, y,
|
||||||
|
fused_yaw)를 대조군으로 병행 로깅**해 SLAM 결과와 비교한다 — 이미 두 소스(엔코더, WitMotion
|
||||||
|
IMU)로 한 번 검증해본 경험이 있으니, 세 번째 소스(라이다 SLAM)까지 서로 얼마나 일치하는지
|
||||||
|
교차검증하면 어느 쪽이 이 환경에서 더 신뢰할 만한지 판단할 근거가 생긴다.
|
||||||
|
* **게이트**: 야외 실주행 중 SLAM 드리프트가 왕복 경로 기준으로 실용적인 수준(예: 수십 미터
|
||||||
|
주행에 수십 cm 이내)인지 확인해야 다음 단계로 넘어간다.
|
||||||
|
|
||||||
|
### Phase 4 — 아키텍처 결정 + 저위험 프로토타입 (모터 제어에 처음으로 연결, 자동 개입은 없음)
|
||||||
|
|
||||||
|
* §7.4.2의 (A) Nav2 완전 이관 / (B) 얇은 브릿지 중 방향을 확정한다.
|
||||||
|
* (A)라면: Nav2 스택(costmap, 플래너)을 세팅하고, §7.4.4에서 설명한 **ros2_control 하드웨어
|
||||||
|
인터페이스(`hardware_interface::SystemInterface`)를 작성**해 `xbox_motor_control.cpp`의
|
||||||
|
ZLAC8015D 통신/킨매틱스/안전로직을 이식하고 URDF의 `<ros2_control>` 태그로 선언한다. 컨트롤러
|
||||||
|
(`diff_drive_controller` 재사용 또는 커스텀 스킷스티어 컨트롤러)까지 붙이되, **경로/속도명령이
|
||||||
|
실제로 잘 나오는지만 확인** — 아직 ros2_control 노드가 실제 모터로 명령을 내보내지 않도록
|
||||||
|
하드웨어 인터페이스 안에서 출력을 로그로만 찍고, RViz 등에서 시각적으로만 검증.
|
||||||
|
* (B)라면: 웨이포인트를 받아 방향/거리를 계산하는 브릿지 코드를 작성하되, 처음엔 **콘솔에
|
||||||
|
"이 방향으로 가라"만 출력**하고 실제 `setRPMs()` 호출은 아직 연결하지 않는다. 이 경로는
|
||||||
|
ros2_control 없이도 진행 가능하다(§7.4.2 참고).
|
||||||
|
* **게이트**: 두 경우 모두 "이 로봇이 지금 어디로 가야 하는지"에 대한 판단이 사람이 보기에
|
||||||
|
타당한지부터 확인한 뒤에야 실제 구동을 연결한다 — 잘못된 목표를 실제 바퀴에 바로 연결하면
|
||||||
|
위험하다.
|
||||||
|
|
||||||
|
### Phase 5 — 통제된 구역 폐루프 자율주행 첫 테스트
|
||||||
|
|
||||||
|
* 울타리 등으로 막힌 좁은 구역, 저속, 사람이 항시 대기하며 즉시 개입(CH5 브레이크 또는
|
||||||
|
프로그램 종료)할 수 있는 상태에서 첫 자율주행 테스트를 진행한다.
|
||||||
|
* 짧은 웨이포인트(수 미터) 단위로 끊어서 검증 — 한 번에 긴 경로를 맡기지 않는다.
|
||||||
|
* [06번 문서](06-imu-integration-plan.md) Phase 4(전신 슬립 감지)가 자율주행 중에도 그대로
|
||||||
|
살아있는지, 즉 SLAM/Nav2 경로를 따라가는 도중에도 슬립 감지 시 속도를 낮추는 안전장치가
|
||||||
|
정상 작동하는지 반드시 같이 확인한다.
|
||||||
|
* **게이트**: 짧은 구간에서 반복 검증이 안정적이어야 범위를 넓힌다.
|
||||||
|
|
||||||
|
### Phase 6 — 범위 확장
|
||||||
|
|
||||||
|
* 더 길고 개방된 구역, 동적 장애물(사람/다른 물체 이동) 대응, Nav2 로컬 코스트맵과 기존
|
||||||
|
전신 슬립 감지·바퀴 이상 진단을 함께 쓰는 이중 안전 체계로 확장한다.
|
||||||
|
|
||||||
|
## 7.6 규모감
|
||||||
|
|
||||||
|
[06번 문서](06-imu-integration-plan.md)의 Phase 1~5a는 전부 `xbox_motor_control.cpp` 한 파일
|
||||||
|
안에서의 점진적 추가였다. 이번 작업은 **완전히 다른 소프트웨어 스택(ROS2)을 새로 설치·구성**하고
|
||||||
|
별도 패키지들을 빌드해야 하는, 성격이 다르고 규모가 훨씬 큰 작업이다. (A) 경로를 선택하면
|
||||||
|
SLAM 패키지 도입뿐 아니라 **URDF 작성 + `xbox_motor_control.cpp`의 하드웨어/킨매틱스 로직을
|
||||||
|
ros2_control 하드웨어 인터페이스로 이식**하는 작업까지 포함되므로, 사실상 이 프로그램의 실행
|
||||||
|
레이어 전체를 ROS2 표준 구조로 재작성하는 셈이다 — §7.4.4 참고.
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
# 08. 로봇 제어 시스템 개선 보고서
|
||||||
|
|
||||||
|
> 이 문서는 `feat/radiomaster-rc-control` 브랜치에서 진행한 개선 작업을 정리한 보고서다.
|
||||||
|
> 모든 항목은 실제 로봇 실주행 로그로 검증을 거쳤으며, 정량적 결과는 실측 CSV 로그 분석
|
||||||
|
> 기반이다. 관련 상세 계획/근거는 [06-imu-integration-plan.md](06-imu-integration-plan.md),
|
||||||
|
> [joystick.md](joystick.md)에 별도로 정리되어 있다.
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
기존 Xbox 컨트롤러(SDL2) 기반 조종을 RadioMaster Pocket + XR1 RC 수신기로 교체하면서 시작해,
|
||||||
|
IMU(WitMotion HWT905) 도입을 통해 로봇이 "지령한 대로 실제로 움직이고 있는지"를 처음으로
|
||||||
|
확인·보정할 수 있게 만들었다. 그 결과 제자리 회전 성능이 지령 대비 실측 기준 **44~58% →
|
||||||
|
93.6%**로 크게 개선되었고, 직진 헤딩 자동 유지, 전신 슬립 감지, 모터 과열 조기 감지 등의
|
||||||
|
안전/편의 기능이 추가되었다.
|
||||||
|
|
||||||
|
## 1. RC 조종 시스템 전환
|
||||||
|
|
||||||
|
* Xbox/SDL2 조이스틱을 RadioMaster Pocket + XR1 수신기(CRSF 프로토콜, 420000bps)로 교체.
|
||||||
|
* 실측 하드웨어 캘리브레이션(CH1 조향/CH2 전후진/CH5 브레이크/CH6 속도모드) 및 Fail-safe
|
||||||
|
타임아웃 적용.
|
||||||
|
|
||||||
|
**문제**: 실측 중 채널 값이 간헐적으로 엉뚱한 값으로 튀는 현상 발견(예: 스틱을 살짝만
|
||||||
|
움직였는데 최대 후진값이 순간적으로 찍힘). CRSF 프로토콜은 표준상 CRC-8 체크섬으로 손상된
|
||||||
|
프레임을 걸러낼 수 있는데, 이 특정 수신기 하드웨어에서는 표준 CRC-8(DVB-S2) 및 가능한
|
||||||
|
변형(다항식/초기값/반전 조합 전수조사, 보율 오차 가설 등)을 모두 실측 데이터로 대조해봐도
|
||||||
|
일치율이 최대 33%에 그쳐 **이 하드웨어에서는 CRC 검증 자체가 신뢰할 수 없다**는 결론을 실험적으로
|
||||||
|
확정.
|
||||||
|
|
||||||
|
**적용 방식**: CRC 대신 3단계 방어를 조합했다.
|
||||||
|
1. **범위 검증**: 캘리브레이션으로 확인된 정상 범위를 벗어나는 값은 무조건 거부.
|
||||||
|
2. **슬루레이트(변화율) 제한**: 한 틱 사이에 물리적으로 불가능할 만큼 큰 변화는 손상 프레임으로
|
||||||
|
간주해 거부하되, 진짜 빠른 스틱 조작까지 막지 않도록 N틱 연속 거부되면 강제로 재동기화하는
|
||||||
|
예외 처리를 둠(그렇지 않으면 채널이 영구히 멈추는 결함이 있었음 — 발견 후 수정).
|
||||||
|
3. **중앙값(median-of-3) 필터**: 최근 3개 값의 중앙값을 취해 단발성 튐값의 영향을 한 번 더
|
||||||
|
줄임.
|
||||||
|
* udev 규칙으로 `/dev/ttyMOTOR`/`/dev/ttyRC`/`/dev/ttyIMU` 고정 심볼릭 링크 적용 — USB 재연결
|
||||||
|
시 포트 번호가 매번 바뀌던 문제 해결.
|
||||||
|
|
||||||
|
## 2. 주행 제어 안정성 개선
|
||||||
|
|
||||||
|
* **브레이크**: 기존엔 스로틀을 중립으로 되돌려 자연 정지할 때도 전자식 브레이크가 자동으로
|
||||||
|
잠겼는데, 이를 CH5 스위치를 눌렀을 때만 잠기도록 변경.
|
||||||
|
|
||||||
|
* **가속/감속 — 저크 제한(jerk-limited) S-curve란**: 속도(RPM)를 목표까지 바로 바꾸는 게 아니라,
|
||||||
|
"가속도가 변하는 속도(저크)" 자체에 상한을 둬서 가속도 곡선을 매끄러운 S자로 만드는 방식이다.
|
||||||
|
급격한 가속도 변화는 큰 전류 스파이크(역기전력)로 이어질 수 있어, 감속에는 계속 이 방식을
|
||||||
|
유지한다. 다만 하드웨어 백EMF 보호회로 구성이 완료되면서 **가속은 더 이상 소프트웨어로 완만하게
|
||||||
|
램프업할 필요가 없어져, 조이스틱 목표값에 1:1로 즉시 추종하도록 변경**했다(감속은 기존과 동일).
|
||||||
|
|
||||||
|
* **정지 직전 반전 방지**: 위 "즉시가속" 로직은 "목표값이 현재값보다 커지면 무조건 즉시 반영"
|
||||||
|
하는 단순 조건이었는데, 정지 막바지 저속 구간에서 RC 노이즈로 목표값이 순간적으로 반대 부호로
|
||||||
|
흔들리면 이 조건이 그대로 성립해버려 "전진→후진→전진"처럼 튀는 현상이 있었다. **적용 방식**:
|
||||||
|
조건을 "같은 방향으로 더 빨라지는 경우"로 한정하고, 부호가 바뀌는 경우(RC 노이즈든 실제
|
||||||
|
방향 전환 지시든)는 전부 저크 제한 감속 경로로 보내 0을 관통할 때도 부드럽게 처리하도록 수정.
|
||||||
|
|
||||||
|
## 3. IMU 통합 — 오도메트리 (Phase 1~2)
|
||||||
|
|
||||||
|
* WitMotion HWT905-RS232 IMU를 별도 USB 포트로 연동, 전원 인가 시점의 방향을 정면(0°) 기준으로
|
||||||
|
저장.
|
||||||
|
|
||||||
|
**적용 방식 — 데드 레커닝(dead reckoning)**: GPS 없이 "지금까지 어느 방향으로 얼마나 움직였는지"를
|
||||||
|
누적 적분해서 현재 위치(x, y)를 추정하는 고전적 방식이다. 매 제어 주기(틱)마다 (1) 바퀴 인코더
|
||||||
|
피드백으로 계산한 이동 속도와 (2) 그 순간의 헤딩(진행 방향)을 곱해 이동한 x, y 변위를 누적한다.
|
||||||
|
정확도는 전적으로 **헤딩을 얼마나 정확히 아는가**에 달려 있다 — 헤딩이 조금만 틀려도 매 틱
|
||||||
|
누적되며 오차가 기하급수적으로 벌어지기 때문에, 이번 작업에서 가장 공들인 부분이 헤딩 소스
|
||||||
|
선정이었다.
|
||||||
|
|
||||||
|
* 바퀴 엔코더 기반 위치 적분(x, y)과 회전율(wheel_omega) 대 IMU 실측 회전율(imu_omega) 비교
|
||||||
|
로직 추가.
|
||||||
|
* **헤딩 소스 결정 — 실측 검증으로 설계를 뒤집은 사례**: 처음엔 상식적으로 "IMU 자체 내장
|
||||||
|
융합 yaw(가속도+자이로를 자체적으로 결합해 계산한 값)가 원시 자이로를 그냥 적분하는 것보다
|
||||||
|
안정적일 것"이라 예상하고 그렇게 구현했다. 그런데 **검증 방법으로 "제자리로 돌아오는
|
||||||
|
루프백 주행"을 설계**해서(직선/원 등 정해진 경로로 나간 뒤 출발점으로 복귀시켜, 오차가
|
||||||
|
없다면 최종 위치가 (0,0)에 가까워야 한다는 원리) 실측해보니 시작점 대비 **20.8m나 이탈**하는
|
||||||
|
심각한 오차가 나왔다. 원인을 더 파보니 IMU가 자체적으로 계산해 내놓는 융합 yaw가 **자기
|
||||||
|
자신의 원시 자이로 방향과도 1초 평균 기준 72%밖에 일치하지 않음**을 발견했다(저가 IMU가
|
||||||
|
모터 전류로 인한 자기장 간섭 등으로 내부 지자기 보정이 흔들리는 것으로 추정). **이후 헤딩
|
||||||
|
소스를 바퀴 인코더로 추정한 회전율과 원시 자이로 값의 평균(단순 상보 융합)으로 교체** —
|
||||||
|
이 두 신호는 서로 독립적인 센서(엔코더 vs IMU)인데도 부호/크기 일치율이 99.3%로 매우
|
||||||
|
높아 신뢰할 수 있음을 먼저 확인한 뒤 채택했다.
|
||||||
|
* **재검증**: 동일한 루프백 테스트를 다시 수행해 이탈 거리가 **20.8m → 0.55m**로 개선됨을
|
||||||
|
확인(22m 주행 기준 약 2.5% 오차) — 같은 검증 방법을 "전/후 비교"에도 그대로 재사용해
|
||||||
|
설계 변경의 효과를 정량적으로 입증했다.
|
||||||
|
|
||||||
|
## 4. 직진 헤딩 자동 유지 (Phase 3)
|
||||||
|
|
||||||
|
* 조향이 중립이고 실제로 주행 중이며 라이다 회피가 개입하지 않을 때, 진입 시점의 헤딩을
|
||||||
|
목표로 고정하고 **PI 제어**로 좌우 편향을 자동 보정.
|
||||||
|
|
||||||
|
**적용 방식 — PI 제어**: 목표 헤딩과 현재 헤딩의 차이(오차)를 계속 관찰하면서, (1) **P(비례)항**
|
||||||
|
— 오차가 클수록 더 크게 보정하고, (2) **I(적분)항** — 작은 오차가 오래 지속되면(예: 좌우 노면
|
||||||
|
마찰 차이로 인한 지속적 편향) 그것까지 누적해서 보정을 강화하는 두 요소를 더해 좌우 바퀴 속도에
|
||||||
|
미세한 트림(보정값)을 얹는 방식이다. 트림 값에는 상한을 둬서 사용자의 의도적 조향 입력을 절대
|
||||||
|
압도하지 않도록 제한했고, 적분항에도 별도 상한(anti-windup)을 둬 트림이 무한정 커지는 것을 방지.
|
||||||
|
|
||||||
|
* 실주행 검증(다양한 노면, 총 20분 이상): 평균 오차 0.48~1.24°, 최대 오차 10° 이내, 트림
|
||||||
|
값은 상한(±0.15 rad/s)의 최대 38%까지만 사용 — 포화·진동 없이 안정적으로 수렴.
|
||||||
|
|
||||||
|
## 5. 전신 슬립 감지 (Phase 4)
|
||||||
|
|
||||||
|
**적용 방식 — 독립 신호 교차검증**: 기존 걸림/들뜸 판정은 "지령 RPM 대비 실제 RPM"과
|
||||||
|
"전류"만으로 개별 바퀴 상태를 추정하는데, 이 두 값 모두 바퀴 자체(엔코더/전류 센서)에서
|
||||||
|
나오는 신호라 만약 4바퀴가 동시에(예: 빙판·젖은 잔디) 헛돌면 "다들 정상적으로 지령을
|
||||||
|
따라가는 것처럼" 보여 잡아내지 못하는 사각지대가 있다. 그래서 **바퀴 시스템과 완전히
|
||||||
|
독립적인 IMU(관성 센서)로 실제 차체가 얼마나 돌고 있는지를 직접 재서 지령값과 비교**하는
|
||||||
|
이중 안전망을 추가했다: 지령 회전율과 IMU 실측 회전율의 비율이 임계값 밑으로 일정 시간
|
||||||
|
지속되면 "전신 슬립"으로 판정해 라이다 회피의 감속 패턴과 동일한 방식으로 속도를 일시적으로
|
||||||
|
낮춘다. 제자리 회전은 원래도 지령보다 덜 도는 게 정상(스크럽 마찰)이라, 오탐을 피하기 위해
|
||||||
|
"거의 안 도는" 극단적인 경우만 잡히도록 문턱값을 보수적으로 설정.
|
||||||
|
|
||||||
|
* 18분 실주행 중 11회, 0.4%의 틱에서만 발동 — 오탐 거의 없음. 가장 긴 발동 사례(1.68초)를
|
||||||
|
분석한 결과, 고속 주행 중 급선회 시 관성으로 인한 언더스티어(로봇이 거의 안 도는 상황)를
|
||||||
|
정확히 감지해 속도를 절반으로 낮췄고, 그 직후 실제로 회전이 정상적으로 회복되는 것을 확인
|
||||||
|
— 설계 의도대로 작동.
|
||||||
|
|
||||||
|
## 6. 킨매틱스 실측 캘리브레이션 — 제자리 회전 성능 대폭 개선 (Phase 5a)
|
||||||
|
|
||||||
|
### 6.1 원인 진단
|
||||||
|
|
||||||
|
제자리 회전이 지령한 만큼 돌지 않는 문제의 원인을 로그로 추적한 결과, 두 가지가 확인됨:
|
||||||
|
|
||||||
|
1. 회전 시 반력 토크로 인한 대각선 방향 하중 이동(FL+RR 또는 FR+RL 바퀴 쌍이 동시에
|
||||||
|
가벼워짐)이 정상적인 물리 현상인데, 기존 "들뜸(바퀴가 지면에서 떨어짐)" 판정 로직이 이를
|
||||||
|
오탐하여 목표 속도를 0으로 꺼버려 4륜 중 사실상 2륜만 구동되는 상황이 전체 회전 틱의
|
||||||
|
**38%**에서 발생.
|
||||||
|
2. 회전 반경 계산에 쓰이는 트랙폭 계수(`k_skid`, `effective_w`)가 기하학적 공식값으로,
|
||||||
|
실제 스킷스티어 특유의 스크럽 마찰(바퀴가 옆으로 긁히며 도는 저항)을 반영하지 못해
|
||||||
|
지령보다 작은 차동 속도를 걸고 있었음.
|
||||||
|
|
||||||
|
### 6.2 조치 및 결과
|
||||||
|
|
||||||
|
* 제자리 회전 중에는 "들뜸" 판정으로 목표 속도를 꺾는 개입을 비활성화(판정 표시는 유지).
|
||||||
|
|
||||||
|
**적용 방식 — 실측 역산(파라미터 피팅)**: 기존 `k_skid`/`effective_w`는 로봇의 트랙폭·휠베이스
|
||||||
|
치수만으로 계산한 순수 기하학적 공식값이었는데, 실제 지면에서는 바퀴가 옆으로 긁히는 저항
|
||||||
|
때문에 이 공식이 가정하는 것보다 더 큰 차동을 걸어줘야 같은 회전 속도가 나온다. 이를 정량화하기
|
||||||
|
위해 매 틱 로그에 이미 기록되고 있던 "바퀴 인코더로 계산한 회전율"과 "IMU로 실측한 실제
|
||||||
|
회전율"을 이용해, 공식을 거꾸로 풀어서(예: `유효계수 = 바퀴 기반 회전율 추정치 × 기존계수 ÷
|
||||||
|
IMU 실측 회전율`) **틱마다 "실제로 맞았어야 할 계수값"을 역산**했다. 이렇게 나온 수천 개의
|
||||||
|
값 중 이상치 영향을 줄이기 위해 평균이 아닌 **중앙값**을 대표값으로 채택했고, 서로 다른 날
|
||||||
|
수집한 **3차례의 독립적인 실주행 로그**에서 반복 계산해도 값이 거의 같게 수렴하는 것을
|
||||||
|
확인해 신뢰도를 높였다. 회전 반경별로 값을 나눠 보면 완만한 커브(0.44)와 급한 커브(0.53)
|
||||||
|
사이에서 계수가 변하는 경향도 확인했는데, 정적 상수 하나로는 이 편차를 완전히 없앨 수
|
||||||
|
없어 실용적인 절충값(중앙값)을 채택 — 이걸 실시간으로 자동 보정하는 방식(Phase 5b)도
|
||||||
|
검토했으나, 슬립이 발생하는 바로 그 순간에 추정 신호 자체가 같이 왜곡되는 구조적 문제가
|
||||||
|
있어 득보다 실이 크다고 판단해 보류했다. 아래 값으로 최종 수렴:
|
||||||
|
|
||||||
|
| 파라미터 | 기존(기하학적 공식) | 실측 캘리브레이션 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `k_skid` (커브 선회) | 0.406 | **0.51** |
|
||||||
|
| `effective_w` (제자리 회전) | 0.684 | **0.87** |
|
||||||
|
|
||||||
|
* **최종 성능**: 제자리 회전 시 지령 대비 실제 회전율(IMU 실측 기준)이 **44~58% → 93.6%**로
|
||||||
|
개선. 완전히 100%에 도달하지 못하는 잔여 오차는 스킷스티어 구조 특유의 물리적 한계(4륜
|
||||||
|
전부가 옆으로 긁히며 돌아야 하는 구조상 슬립 없이는 방향 전환이 불가능)로 판단되며, 현재
|
||||||
|
수준이 이 하드웨어에서 실용적으로 기대 가능한 한계에 근접한 것으로 평가.
|
||||||
|
* 실시간 온라인 적응형 보정(Phase 5b)은 추가 정확도 이득 대비 구현/검증 리스크가 크다고
|
||||||
|
판단해 보류 결정(근거는 06번 문서 참고).
|
||||||
|
|
||||||
|
## 7. 모터/드라이버 온도 모니터링
|
||||||
|
|
||||||
|
* 기존엔 사용하지 않던 드라이버 레지스터(모터 온도 `0x20A4`, 드라이버 온도 `0x20B0`)를 읽어
|
||||||
|
HUD/CSV에 실시간 노출.
|
||||||
|
|
||||||
|
**적용 방식**: 드라이버와의 통신은 매 제어 주기(약 27Hz)마다 이루어지는데, 통신 1회를 늘릴
|
||||||
|
때마다 제어 루프 지연이 커진다. 모터 온도 레지스터(`0x20A4`)는 마침 기존에 읽고 있던
|
||||||
|
레지스터 범위(`0x20A5`~) 바로 앞이라, **읽는 레지스터 개수만 하나 늘려서 통신 횟수 추가 없이**
|
||||||
|
얻어냈다. 반면 드라이버 자체 온도(`0x20B0`)는 기존 읽기 범위와 떨어져 있어 합치면 통신이
|
||||||
|
늘어나는데, 온도는 물리적으로 초 단위로 천천히 변하는 값이라 매 틱 갱신할 필요가 없다는 점을
|
||||||
|
이용해 **약 1.1초에 한 번만 별도로 폴링**하는 저빈도 방식을 택했다 — 정확도 손실 없이 통신
|
||||||
|
비용을 최소화한 설계.
|
||||||
|
* 60℃ 이상 시 HUD에 경고 표시.
|
||||||
|
|
||||||
|
## 8. 진단만 완료, 조치는 보류 중인 이슈
|
||||||
|
|
||||||
|
* **급정지 시 미세한 요잉(회전) 현상**: 처음엔 "조이스틱을 놓을 때 튕기는 물리적 반동" 가설을
|
||||||
|
세우고 로그의 RC 원시값 변화를 직접 확인했으나, 해당 구간에서 스틱 값은 매끄럽게 중립으로
|
||||||
|
복귀했을 뿐 반대 방향으로 튀는 값은 전혀 없어 이 가설은 기각했다. 대신 정지 이벤트마다
|
||||||
|
전후 바퀴 명령/피드백/상태 플래그를 시간순으로 대조해본 결과 두 가지 원인을 확인:
|
||||||
|
(1) 거친 노면에서 정지 직전 특정 바퀴가 순간적으로 "들뜸" 판정되어 다른 바퀴와 감속 타이밍이
|
||||||
|
어긋나는 것, (2) 드라이버 자체의 속도 제어 루프가 급정지 시 0을 살짝 지나쳤다 돌아오는
|
||||||
|
오버슈트(4바퀴가 0을 지나치는 타이밍이 서로 달라 그 사이 짧게 회전 모멘트가 생김). 감속
|
||||||
|
속도를 낮추면 완화될 여지가 있으나 "즉각 정지" 체감이 희생되는 트레이드오프가 있어 적용
|
||||||
|
여부는 보류 중.
|
||||||
|
|
||||||
|
## 9. 자동화 및 진단 인프라
|
||||||
|
|
||||||
|
* 매 주행마다 `logs/` 폴더에 타임스탬프 CSV 자동 저장(수동으로 `--log` 지정할 필요 없음) —
|
||||||
|
RC/IMU/모터 피드백/오도메트리/헤딩홀드/슬립감지/온도까지 전 항목 기록, 이번 보고서의 모든
|
||||||
|
정량적 검증이 이 로그를 근거로 이루어짐.
|
||||||
|
|
||||||
|
## 10. 향후 계획
|
||||||
|
|
||||||
|
라이다(Livox Mid-360S) 기반 SLAM/자율주행 확장 계획은
|
||||||
|
[07-lidar-slam-plan.md](07-lidar-slam-plan.md)에 별도 정리되어 있음(아직 미착수).
|
||||||
|
|
||||||
|
## 종합 결과 요약
|
||||||
|
|
||||||
|
| 항목 | 개선 전 | 개선 후 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| 조종기 | Xbox/SDL2 (유선) | RadioMaster Pocket + XR1 (무선 RC) |
|
||||||
|
| 브레이크 | 자연 정지 시에도 자동 잠김 | CH5로만 제어 |
|
||||||
|
| 헤딩 인지 | 없음 | 오도메트리(x,y,θ) + 자동 직진 유지 |
|
||||||
|
| 제자리 회전 정확도(지령 대비) | 44~58% | 93.6% |
|
||||||
|
| 슬립 감지 | 개별 바퀴 전류 기반만 존재 | + IMU 기반 전신 슬립 이중 감지 |
|
||||||
|
| 모터 상태 가시성 | 전류만 | + 온도(모터/드라이버) 실시간 감시 |
|
||||||
|
| 주행 기록 | 수동 `--log` 필요 | 매 주행 자동 저장 |
|
||||||
+2
-1
@@ -25,7 +25,8 @@
|
|||||||
| [03-system-architecture.md](03-system-architecture.md) | 로봇 물리 제원, 2드라이버×4모터 매핑, 스키드 스티어 운동학 |
|
| [03-system-architecture.md](03-system-architecture.md) | 로봇 물리 제원, 2드라이버×4모터 매핑, 스키드 스티어 운동학 |
|
||||||
| [04-software-control.md](04-software-control.md) | `xbox_motor_control.cpp` 제어 루프/클래스 구조 분석 |
|
| [04-software-control.md](04-software-control.md) | `xbox_motor_control.cpp` 제어 루프/클래스 구조 분석 |
|
||||||
| [05-error-troubleshooting.md](05-error-troubleshooting.md) | 알람 에러코드 표, 휠 이상(들뜸/걸림) 진단, 전류 한계 튜닝, 트러블슈팅 |
|
| [05-error-troubleshooting.md](05-error-troubleshooting.md) | 알람 에러코드 표, 휠 이상(들뜸/걸림) 진단, 전류 한계 튜닝, 트러블슈팅 |
|
||||||
| [06-imu-integration-plan.md](06-imu-integration-plan.md) | **(계획안, 미구현)** IMU 도입을 통한 제어 고도화 조사 및 단계별 계획 — Husky/논문 비교 |
|
| [06-imu-integration-plan.md](06-imu-integration-plan.md) | IMU 도입을 통한 제어 고도화 조사 및 단계별 계획 — Husky/논문 비교 (Phase 1~5a 구현 완료) |
|
||||||
|
| [07-lidar-slam-plan.md](07-lidar-slam-plan.md) | **(계획안, 미구현)** Livox Mid-360S 기반 LiDAR SLAM 도입 계획 (Phase 6) |
|
||||||
|
|
||||||
06번 문서에 대한 Q&A 기록은 [`../QnA/`](../QnA/) 폴더에 별도로 누적된다 (예: [`q1.md`](../QnA/q1.md) / [`a1.md`](../QnA/a1.md)).
|
06번 문서에 대한 Q&A 기록은 [`../QnA/`](../QnA/) 폴더에 별도로 누적된다 (예: [`q1.md`](../QnA/q1.md) / [`a1.md`](../QnA/a1.md)).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user