실무 프로젝트 : 자율주행(2)

dongmin·2026년 6월 27일
post-thumbnail

저번 포스팅을 한 뒤 대략 1주일이 지났는데 아주 많은 일들이 있었다..
6월 22일까지 미니 프로젝트 완성 기간이었는데 아쉽게 완벽히 완수하지는 못했다.
미니 프로젝트 주제는 다음과 같았다.
웹캠과 rc카, 터틀봇을 사용하는데, 웹캠에 탐지된 rc카의 위치로 터틀봇을 이동시키고 rc카가 움직이면 터틀봇이 tracking 하는 것이 주제였다.

웹캠과 OAK-D 온보드 카메라 연동을 통한 터틀봇4 RC카 자율 추종 시스템

1. 프로젝트 개요 및 아키텍처 구상

미니 프로젝트의 주제는 외부 웹캠과 Turtlebor4를 이용하여 RC카를 실시간으로 탐지하고 자율적으로 추종하는 시스템을 구현하는 것이다.

외부 글로벌 웹캠과 터틀봇4의 OAK-D 카메라를 결합한 하이드비드 센서 구조를 설계하였는데,
프로젝트의 핵심 아이디어는 Coarse-to-Fine 방식이다. 즉, 외부 웹캠이 넓은 공간에서 RC카의 대략적인 위치를 빠르게 찾고, 터틀봇은 해당 위치까지 자율주행으로 이동한 뒤, 마지막 구간에서는 자신의 카메라를 이용하여 정밀하게 RC카를 추적하는 구조이다. 이를 통해 탐색 시간을 줄이면서도 최종적으로는 높은 추종 정확도를 확보하고자 했다.

구상한 시스템의 핵심 메커니즘은 'Coarse-to-Fine(거친 접근 후 정밀 제어)'이다.

  1. Global Detection : 외부 웹캠을 이용한 RC카 탐지
    천장에 설치된 웹캠이 주차장 전체를 실시간으로 촬영하며 YOLO 객체 탐지 모델을 이용하여 RC카를 검출하고 Homography Calibration을 이용하여 ROS2 Map 좌표계의 좌표로 변환한다.

  2. Global Navigation : Nav2를 이용한 자율주행
    웹캠으로부터 RC카의 좌표를 전달받으면 터틀봇은 ROS2 Nav2 스택을 이용하여 해당 위치까지 자율적으로 이동한다.

  3. Local Detection : OAK-D 카메라를 이용한 정밀 탐색
    Staging Point에 도착하면 터틀봇은 자신의 OAK-D RGB 카메라를 이용하여 RC카를 탐색한다. 터틀봇은 제자리에서 회전하며 RC카를 찾고, 객체가 검출되면 BBOX 중심이 화면 중앙에 위치하도록 회전 각속도를 조절한다.

  4. Fine Tracking : RGB + Depth 기반 정밀 추종
    RC카가 화면 중앙에 정렬되면 OAK-D의 Depth 카메라를 이용하여 RC카와의 실제 거리를 측정하고 RC카와의 거리가 30cm 미만이 될 때까지 전진한다.
    RC카가 다시 움직이면 동일한 제어 과정을 반복하여 실시간으로 추종하는 것이 최종 목표이다.

2. 프로젝트 전체 흐름

성공적인 구동을 위해 명령어 실행 전, 단계별로 수행한 사전 빌드업 과정이다. 단순히 코드만 작성한 것이 아니라, 하드웨어와 환경 캘리브레이션을 위해 다음과 같은 작업을 처리했다.

Phase 1. 2D 환경 맵 생성 (SLAM Mapping)

  • 수행한 작업: 터틀봇4의 teleop_twist_keyboard 노드를 실행하여, 수동으로 주행하며 지도를 생성하였는데, 이후 매핑의 정확도를 높이기 위해 explore_lite 패키지를 이용한 Auto SLAM을 도입하였다.

    explore_lite 는 Frontier Exploration(미개척 영역 탐색) 패키지이다.
    SLAM, 즉 지도 생성할 땐 Odometry, LiDAR 센서가 항상 돌아가며 자신의 위치를 추정하고 주변 환경을 스캔합니다.

  • 결과물: 벽면과 장애물이 정밀하게 기록된 2D 점유 격자 지도 파일인 room_map.yamlroom_map.pgm을 생성하고 저장한다.

    room_map.pgm : 실제 지도의 시각 정보
    room_map.yaml : 해상도, 원점 위치, 점유 임계값 등 지도 좌표계 정보

우리 조에서 Auto SLAM으로 생성한 맵 정보는 다음과 같다.

image: room_map.pgm            # 지도 이미지 파일 경로
mode: trinary                  # 지도 데이터의 픽셀값을 [0(빈 공간), 1(장애물), -1(미탐색 영역)]의 세 가지 상태로만 해석한다.
resolution: 0.05               # 지도 데이터의 해상도로 단위는 [미터/픽셀]. 즉 1픽셀이 실제 5cm에 해당
origin: [-2.27, -0.548, 0]     # 지도의 시작점이 실제 맵의 좌표계에서 어디에 위치하는지를 나타낸다. 
negate: 0                      # 이미지 색상 반전 여부
occupied_thresh: 0.65          # 장애물로 판단하는 임계값. 이미지의 픽셀값이 0.65가 넘으면 장애물로 간주
free_thresh: 0.25              # 빈 공간으로 판단하는 임계값. 이미지의 픽셀값이 0.25보다 낮으면 이동 가능 구역으로 간주

Phase 2. 외부 웹캠 좌표계 캘리브레이션 (Homography Matrix)

  • 수행한 작업: 외부 웹캠의 2D 이미지 픽셀 좌표 (u, v)를 ROS2 맵 상의 실제 월드 좌표 (x, y)로 매칭하는 작업이 필요했다. RViz2 상에서 ros2 topic echo /clicked_point --once 명령어를 켠 채, 맵의 특정 네 모퉁이를 클릭하여 정확한 맵 좌표를 얻었다. 동시에 외부 웹캠 영상에서 동일한 위치의 픽셀 좌표를 획득했다.

  • 결과물: 매칭된 4개 이상의 픽셀-맵 좌표 쌍을 webcam_map_calibration.json 파일로 저장했다. 노드가 실행될 때 OpenCV의 cv2.findHomography 함수가 이 데이터를 읽어 원근 왜곡을 보정하는 변환 행렬을 실시간으로 계산한다.

Phase 3. RC카 탐지용 딥러닝 모델 학습 (YOLO Dataset & Training)

본 프로젝트의 핵심인 'RC카 객체 탐지'를 위해 커스텀 데이터셋을 구축하고, 다양한 YOLO 모델을 비교 분석하여 최적의 모델을 선정했다.

  1. 데이터셋 구축 및 라벨링
  • 데이터 수집: 다양한 환경(조명, 구도, 거리)에서 RC카를 촬영하여 원본 이미지를 확보했다. 특히 우리 조의 타겟인 '회색 부가티 RC카'를 중심으로 데이터를 수집했다.
  • 라벨링: LabelImg 툴을 사용하여 이미지를 라벨링했으며, 클래스는 mycar와 blackbox 두 가지로 정의했다.

<labelImg로 바운딩 박스 그리는 사진 필요>

  • 데이터 분할: 총 데이터를 6:2:2 비율로 나누어 훈련(Train), 검증(Val), 테스트(Test) 셋을 구성했다.
  1. 모델 훈련 및 성능 비교 (Benchmarking)
    Google Colab 환경을 활용하여 YOLO 시리즈의 경량화 모델들을 훈련하고 성능을 정량적으로 비교했다.
  • 실험 모델: YOLOv5s, YOLOv8n, YOLO11n
  • 평가 지표: mAP(mean Average Precision)를 통한 정확도와, 엣지 디바이스 환경을 고려한 추론 속도(Inference Time)를 중점적으로 분석했다.

YOLO11n

YOLOv8n

YOLOv5n
  • 결과물: 최종적으로 로봇 엣지 디바이스 환경에서 실시간성(Real-time)을 보장하면서도 높은 신뢰도를 보인 yolo8n으로 훈련한 가중치 파일 best.pt를 도출하여 모델 폴더에 배치했다.

3. 핵심 구동 명령어 및 파라미터 세부 분석

시스템을 가동하기 위해 4개의 독립된 터미널에서 순차적으로 명령어를 실행한다. 각 명령어의 역할과 핵심 파라미터의 의미는 다음과 같다.

터미널 1: 정적 지도 로드 및 위치 추정 (Localization)

ros2 launch turtlebot4_navigation localization.launch.py namespace:=/robot<n> map:<2D 맵 파일 절대 경로>
  • SLAM으로 구축한 2D지도를 이용하여 TurtleBot4가 자신의 현재 위치를 추정하도록 하는 Navigation 시스템을 실행하는 명령어.
  • namespace:=/robot4: 로봇의 토픽 및 노드가 다른 장비와 충돌하지 않도록 네임스페이스를 분리한다.
  • map : 2D 맵 파일의 절대 경로

터미널 2: RViz2 시각화 툴 가동

ros2 launch turtlebot4_viz view_robot.launch.py namespace:=/robot<n>

<RViz2 상에 room_map 불러오는 사진 필요>

  • 터틀봇4의 센서 데이터 상태와 맵, 경로 계획(Path Planning)을 GUI 환경에서 모니터링하기 위한 시각화 프로그램을 실행한다.

  • 역할: 로봇의 파티클 필터가 수렴하여 위치 추정이 잘 되었는지 확인하고, 비전 노드가 발행하는 RC카의 예상 위치 마커(/rc_car/map_marker)를 시각적으로 검증한다.
    Rviz에 맵이 불러와졌으면 로봇의 초기 위치를 잡아주어야 하는데 로봇의 방향도 지정해주어야하기 때문에 2D Pose Estimate 버튼을 클릭하여 초기 위치와 방향을 지정해주었다.

<rviz상에 초기 위치와 방향 지정해주는 사진 필요>

터미널 3: Nav2 자율 주행 스택 실행

ros2 launch turtlebot4_navigation nav2.launch.py namespace:=/robot4

  • 설명: 로봇이 목적지까지 장애물을 피해 스스로 주행할 수 있도록 내비게이션 알고리즘 전체를 가동한다.

  • 역할: 글로벌/로컬 코스트맵(Costmap)을 생성하고 플래너와 컨트롤러를 활성화한다. 이후 메인 제어 노드가 MapsToPose 액션 인터페이스를 통해 목표 좌표를 주면 최적의 회피 경로를 생성하여 바퀴 모터로 속도 명령을 전달한다.

터미널 4: 메인 통합 트래킹 제어 노드 구동 (FSM Core)
로봇이 단순히 RC카를 인식하는 것을 넘어, 자율적으로 추적하고 안전하게 정지하는 제어 로직이다. tracking_node는 4번째 터미널에서 실행되며, 실시간 객체 탐지 데이터와 로봇의 주행 명령을 연결하는 핵심 역할을 한다.

ros2 run webcam_mycar_tracking tracking_node --ros-args \
    -p webcam_realtime_tracking:=true \
    -p model_path:=/home/kim/rokey_ws/src/webcam_mycar_tracking/models/best.pt \
    -p calibration_path:=/home/kim/rokey_ws/src/webcam_mycar_tracking/config/webcam_map_calibration.json \
    -p camera_index:=2 \
    -p cmd_vel_topic:=/robot4/cmd_vel \
    -p robot_base_frame:=base_link \
    -p mycar_class_id:=0 \
    -p confidence_threshold:=0.70 \
    -p stop_distance:=0.30 \
    -p max_linear_speed:=0.15 \
    -p max_angular_speed:=0.25 \
    -p align_gain:=0.4 \
    -p distance_gain:=0.4 \
    -p forward_tolerance:=0.20 \
    -p target_lost_timeout:=2.0 \
    -p show_webcam:=true

튜닝 파라미터 분석

  • -p webcam_realtime_tracking:=true : 외부 웹캠을 통한 실시간 좌표 추적 모드를 활성화한다.

  • --p confidence_threshold:=0.70 : YOLO의 객체 탐지 확률이 70% 이상일 때만 진짜 RC카로 인식하여 노이즈 및 오인식을 필터링한다.

  • --p stop_distance:=0.30 : OAK-D 깊이(Depth) 카메라 기준으로 RC카 전방 30cm(0.3m) 지점에 도달하면 안전하게 정지하도록 설정한다.

  • -p align_gain:=0.4 : 카메라 픽셀 중앙과 객체 중심 간의 오차를 줄이기 위한 회전 비례 제어 게인이다. 이 값이 너무 크면 로봇이 좌우로 심하게 흔들리고(Oscillation), 너무 작으면 정렬 속도가 느려진다. 수많은 실험을 통해 최적의 값인 0.4를 도출했다.

  • -p distance_gain:=0.4 : 타겟과의 잔여 거리에 비례하여 선속도를 줄여주는 직진 비례 제어 게인이다. 목적지에 가까워질수록 부드럽게 감속 정지하도록 만든다.

  • -p target_lost_timeout:=2.0 : 주행 중 장애물이나 각도 문제로 RC카를 놓쳤을 때, 2초 동안은 기존 상태를 유지하며 재탐색을 시도하고, 시간이 초과되면 예외 처리(Recovery) 상태로 전환한다.

처음에는 파라미터들을 코드 내부에 하드코딩하는 방식을 고려하였는데 추적 성능과 안전 거리를 최적화 하기 위해 200번 넘는 반복 테스트를 거치면서 하드코딩의 한계를 실감했다. 값을 수정할 때마다 colcon buildsource 과정을 반복해야하기 때문이다.

💡 팁 : YAML 설정 파일로 관리하기
매번 긴 명령어를 터미널에 입력하는 대신, YAML 파일을 사용하면 관리가 매우 간편해진다고 한다.
1. config/tracking_params.yaml 파일 생성
2. 실행할 때 -p 옵션 대신 --params-file 사용

4. 소프트웨어 제어 로직: 유한 상태 머신 (FSM)

tracking_node.py는 로봇의 주행 안정성과 미션 성공률을 높이기 위해, 유한 상태 머신(Finite State Machine, FSM) 구조로 설계하였다. 단순히 RC카를 따라가는 것을 넘어, 각 상황별 예외 처리와 물리적 제어 안정성을 고려하였다.

  • WAIT_SYSTEM & UNDOCKING : 시스템 초기화 후, 충전 스테이션에 도킹되어 있다면 자동 언도킹을 수행하여 미션을 시작한다.

  • WAIT_WEBCAM : 외부 웹캠이 맵 상의 RC카를 포착할 때까지 대기한다. 이때, 영상 처리 과정에서 발생할 수 있는 좌표값 튐 현상을 방지하기 위해 deque 자료구조를 활용한 미디언 필터링(Median Filter)을 적용했다.

  • NAVIGATING (자율주행 거치): RC카와 너무 근접하면 충돌 위험이 있으므로, _standoff 메서드를 통해 로봇과 RC카 사이의 최적 안전 거리를 기하학적으로 계산하여 해당 지점까지 Nav2를 통해 자율주행한다.

  • SEARCHING : 대기 지점 도착 후, 로봇은 온보드 OAK-D 카메라를 활성화하고 제자리에서 회전하며 RC카의 정확한 방향을 탐색한다.

  • ALIGNING : RGB 화면의 RC카 바운딩 박스를 중앙으로 정렬한다. 이때 지수 이동 평균 필터를 사용하여, 바운딩 박스가 미세하게 흔들려도 로봇이 급하게 조향하지 않고 부드럽게 정렬하도록 설계했다. (5프레임 이상 정중앙 유지 시 다음 단계로 이행)미세 조향 정렬을 수행한다. 5프레임 이상 정중앙에 고정되면 다음 단계로 이행한다.

  • TRACKING : OAK-D의 스테레오 뎁스 데이터를 실시간 융합하여 RC카의 거리를 추적한다.

    • 거리 데이터 필터링: _bbox_depth 메서드에서 깊이 데이터의 노이즈를 제거하기 위해 10% 영역의 중앙값을 추출하고, 유효 범위(0.05m~10m) 내의 값만 사용한다.

    • Visual Servoing: 조향 오차를 보정하는 각속도 제어와 거리에 비례하는 선속도 제어를 결합하여, RC카에 부드럽게 접근한다.

  • STOPPED / RETURNING : 목표 거리(30cm) 안착 시 모터를 정지하고 미션을 종료한다. 타겟 유실 시에는 역방향 회전 재탐색을 수행하거나, 최초 출발 포즈(start_pose)로 복귀하여 안전성을 확보한다.

RC카의 위치 근처까지 터틀봇을 자율주행시키는 것에는 성공했지만, 이후 OAK-D RGB 카메라를 이용한 정밀 추종 단계는 끝내 완성하지 못했다.

가장 어려웠던 부분은 터틀봇이 제자리에서 회전하며 RC카를 탐색하는 과정에서, RGB 카메라 영상의 바운딩 박스가 화면 중앙에 정확히 위치하는 순간 회전을 멈추는 제어였다. 이론적으로는 객체 중심이 화면 중앙에 오면 회전을 종료하고 전진한 뒤, Depth 카메라를 이용해 RC카와의 거리가 30cm가 되었을 때 정지하며, 이후 RC카가 다시 움직이면 실시간으로 추종하는 흐름을 구현하고자 했다.

하지만 실제 환경에서는 터틀봇의 회전 속도, 카메라의 프레임 처리 속도, YOLO 추론 시간, ROS2 메시지 전달 지연이 모두 복합적으로 작용했다. 그 결과, 바운딩 박스가 화면 중앙에 도달하는 순간을 정확하게 포착하지 못했고, 이미 중앙을 지나친 뒤에 제어 명령이 반영되는 경우가 자주 발생했다. 이러한 지연 때문에 로봇이 목표를 지나치며 좌우로 반복해서 흔들리는(Oscillation) 현상이 발생했고, 안정적으로 정렬 상태를 유지한 뒤 추종 단계로 전환하는 데 실패했다.

  1. 프로젝트 성과 및 배운 점

    외부 카메라와 온보드 카메라의 단점을 상호 보완하는 이중 카메라 센서 퓨전 시스템의 유연함을 경험했다.

    픽셀 좌표를 호모그래피 행렬을 통해 실제 물리 맵 공간의 미터(m) 단위 좌표로 변환해 내는 과정에서 수학적 시각 비전 기술의 중요성을 체감했다.

    제어 이론(P-Control)의 게인 값 튜닝에 따라 로봇의 주행 궤적과 거동 안정성이 얼마나 크게 변하는지 실전 데이터로 배울 수 있었던 값진 미니 프로젝트였다.

0개의 댓글