addinedu Physical AI

ROS2 기반 스마트 쇼핑카트 로봇 — ShopPinkki

Pinky Pro 로봇 기반 미니어처 마트에서 고객을 인식·추종하며 쇼핑을 보조하는 자율주행 로봇 시스템 (팀 프로젝트)

ROS2
Python
Nav2
SLAM
YOLO
Raspberry Pi
Flask
PyQt
Gazebo
ArUco

거동이 불편한 어르신이 마트에서 무거운 카트를 끌고 다녀야 한다면?
원하는 상품이 어디 있는지 몰라서 매장을 헤매야 한다면?
결제를 위해 긴 줄을 서서 기다려야 한다면?

쑈삥끼는 마트에서 고객을 따라다니고, 상품 위치를 안내하며, 결제까지 자동 처리하는 스마트 쇼핑카트 로봇입니다.

QR 스캔으로 고객을 인식하고, LLM + Nav2로 상품 위치를 안내하며, 결제 구역 진입 시 자동 결제가 처리됩니다. 2대가 동시에 각각의 고객을 서빙하며, 경로 충돌은 자체 구현한 Fleet Router로 개발했습니다.

QR 등록
고객 추종
상품 안내
장바구니
자동 결제
충전소 복귀
📅 3.5주 · 2026.03.30–04.22 👥 5명 🥇 4팀 중 1등

📝
프로젝트 후기
회고 · 배운 점 · 아쉬운 점
GitHub Repository
addinedu-physicalai-1st/ros-repo-2

Sprint #15 days
Sprint #25 days
Sprint #35 days
Sprint #45 days
03/23
03/30
04/06
04/1304/17
SPRINT #103/23 — 03/27 · 5d
설계 · 기술조사
  • User / System Requirements
  • 맵 디자인 · 시뮬레이션 맵
  • 주제·기술 분담 조사
SPRINT #203/30 — 04/03 · 5d
아키텍처 · 맵 완성
  • System Architecture · ERD
  • State Diagram · 시나리오
  • SLAM 맵 · 실물 맵 완성
SPRINT #304/06 — 04/10 · 5d
핵심 기능 구현
  • customer_ui · admin_ui
  • LLM 가이드 · 인형 추종
  • 장바구니 · admin 이동 명령
SPRINT #404/13 — 04/17 · 5d
통합 · 발표
  • Open-RMF → Fleet Router
  • 결제 · LED · 음성 시도
  • 시나리오 통합 · 데모

📋 Jira Timeline 보기 — 4 Sprints · 67 Issues 클릭하여 펼치기 ▾
S
SPK · 쑈삥끼 / Timeline
woolimi.atlassian.net
✓ 67 Done 4 Epics
EPIC / ISSUE
Mar 23
Mar 30
Apr 6
Apr 13
Apr 20
SPK-5 프로젝트 설계 및 기술조사 21 issues
SPK-5 · Mar 26 → Apr 10
SPK-19 System Requirements 마무리
SPK-28 software architecture
SPK-53 open rmf 기술조사
SPK-6 Implementation 34 issues
SPK-6 · Mar 26 → Apr 17
SPK-77 Admin UI · Open-RMF 이동
SPK-84 Guide 안내 기능 ← SPK-77
SPK-78 Customer UI 버그 수정
SPK-79 실시간 카트 표시 ← SPK-78
SPK-80 STATUS LED 구현 ← SPK-79
SPK-92 LOCKED 상태 전이
SPK-93 HALTED/LOCKED 관리자 ← SPK-92
SPK-7 발표 자료 준비 1 issue
SPK-7 · Mar 26 → Apr 17
SPK-85 발표준비 · 6 시나리오 데모
SPK-23 맵 만들기 7 issues
SPK-23 · Mar 28 → Apr 9
SPK-17 실제 맵 만들기
SPK-20 맵 디자인
SPK-33 맵 정보 업데이트

  • 플랫폼: Pinky Pro (Pinklab) × 2대
  • 컴퓨팅: Raspberry Pi 5 (8GB)
  • 센서: RPLiDAR + 카메라 + IMU
  • 구동: 2륜 구동 · 다이나믹셀
  • 출력장치: LCD + LED + 부저
Pinky Pro 로봇

미니어처 마트(188 × 141 cm)에서 로봇 2대를 동시에 운용했습니다. 로봇이 작아서 실제 사람을 인식하기 어렵기 때문에, 커스텀 학습된 YOLOv8 모델로 인형을 추종 대상으로 사용했습니다.

매장 2D 도면 매장 구역 배치 실제 매장 맵 Gazebo 시뮬레이션

로봇이 IDLE 상태일 때 LCD에 QR 코드가 표시됩니다. 고객이 스마트폰으로 QR을 스캔하면 웹앱에 접속할 수 있고, 카메라 앞에 인형을 보여주면 ReID 특징 벡터와 HSV 색상 히스토그램이 등록되어 추종이 시작됩니다.

로봇 LCD

로봇이 IDLE 상태일 때 LCD에 QR 코드를 표시합니다. 고객이 스마트폰으로 스캔하면 고객 웹앱에 접속할 수 있습니다.

고객 웹앱
추종 시작
인형 등록

카메라 앞에 인형을 보여주면 ReID 특징 벡터와 HSV 색상 히스토그램이 등록됩니다. 등록이 완료되면 로봇이 해당 인형을 주인으로 인식하고 추종을 시작합니다.

4단계 파이프라인으로 주인 인형을 실시간 추종합니다.

커스텀 YOLOv8 — SAM3(Segment Anything Model)로 라벨링한 300장의 데이터로 인형 전용 모델을 훈련시켰습니다.

ByteTracker — 프레임 간 동일 객체를 이어붙이는 다중 객체 추적 알고리즘입니다. model.track(img, persist=True)로 적용하며, 각 감지된 인형에 고유 track_id를 부여합니다. 화면에서 나갔다가 다시 들어오면 새로운 ID를 받기 때문에, 아래의 ReID로 주인을 식별해야 합니다.

ReID + HSV — ReID는 이미지를 512차원 특징 벡터로 변환해서 코사인 유사도로 비교합니다. HSV 히스토그램 상관계수(≥0.25)를 보조로 사용하여, 비슷하게 생긴 다른 인형에 대한 오인식을 줄였습니다. 조명 변화에도 강합니다.

PI/P 제어 — bbox 크기로 선속도를 PI 제어합니다. P만 사용하면 TARGET에 닿기 직전 마찰 때문에 멈춰버리는 정상상태 오차가 발생해서 I를 추가했습니다. 각속도는 bbox 중심 X좌표로 P 제어하며, deadzone ±45px을 두어 미세한 떨림을 방지했습니다.

고객이 웹앱에서 "음료수 어디 있어?"라고 텍스트를 입력하면 다음 파이프라인을 거칩니다:

  1. 입력 방어 — 매장과 무관한 질문 필터링
  2. 키워드 매칭 — DB 상품명과 직접 매칭 시도
  3. 시맨틱 검색 — 임베딩 벡터 코사인 유사도로 유사 상품 검색
  4. LLM 폴백 — Qwen 2.5가 자연어를 분석해 zone_id 반환
  5. Nav2 자율주행 — DB에서 좌표 조회 후 해당 구역까지 자율 이동, 도착 시 고객에게 알림

스마트폰 카메라로 상품의 QR 코드를 스캔하면 장바구니에 자동으로 추가됩니다. 상품명과 가격이 실시간으로 웹앱에 반영되며, 항목별 삭제도 가능합니다. 결제 시에는 is_paid=0인 항목만 결제 대상이 됩니다.

사용자가 자리를 비울 때 앱에서 [대기하기]를 누르면 로봇이 정지합니다. 대기 중에 RPLiDAR 전방 반원 내에서 근접 통행자를 감지하면 좌우 중 여유 공간이 더 넓은 쪽으로 Nav2 측방 이동(~0.3m)하여 통행로를 확보합니다. 일정 시간 내에 복귀하지 않으면 장바구니 상태에 따라 LOCKED(미결제 물건 있음) 또는 RETURNING(빈 카트)으로 자동 전환됩니다.

BoundaryMonitor가 AMCL 위치 기반으로 체크아웃존 진입을 감지하면 앱에 결제 팝업이 자동으로 표시됩니다. 미결제 상태(TRACKING)에서는 출구 방향 이동이 차단되며, 결제 완료 후 TRACKING_CHECKOUT 상태로 전환되어 출구 통과가 허용됩니다. 결제 구역 안쪽으로 재진입하면 다시 TRACKING으로 전환되어 추가 쇼핑이 가능합니다.

쇼핑이 종료되면 로봇이 Nav2를 통해 충전소로 자율 복귀합니다. 로봇의 현재 위치에 따라 경로가 분기됩니다. 결제구역이나 출구 근처에서는 좁은 통로를 경유(inflation OFF)한 뒤 fleet 그래프 경로로 합류하고, 일반 매장 내부에서는 fleet 그래프 경로로 직행합니다. 미결제 물건이 있을 경우에는 LOCKED 상태로 LED 잠금 신호를 유지한 채 귀환합니다.

PyQt6 기반 관제 앱으로 로봇 2대의 실시간 위치, 상태, 배터리를 모니터링할 수 있습니다. 강제 귀환, 위치 조정, 세션 종료 등의 원격 명령이 가능합니다.

Admin UI Fleet Map

고객 등록 → 추종 → 상품 검색 → 장바구니 → 결제 → 복귀까지의 전체 흐름입니다.

분류기술
로봇ROS 2 Jazzy, Nav2, SLAM, Open-RMF
언어Python, C++
AI / 인식YOLOv8, ByteTrack, ReID, LLM (Qwen 2.5)
시뮬레이션Gazebo, RViz
서버 / DBFlask, SocketIO, PostgreSQL, Docker
UIPyQt6 (Admin), HTML/JS (Customer Web)
하드웨어Raspberry Pi 5, RPLiDAR, Dynamixel

가장 고생했던 부분이 Nav2 파라미터 튜닝이었습니다. 1.4 × 1.8m 미니어처 마트에서 로봇이 선반에 부딪히지 않으면서 좁은 통로를 빠져나가야 하는데, 처음에 inflation_radius를 0.05로 설정했더니 통로 자체를 장애물로 인식해서 경로를 아예 못 찾았습니다. 0.025로 줄여봤더니 이번엔 경로는 찾는데 선반 모서리를 스치면서 지나가서 위험했고요. 결국 0.01까지 내렸더니 겨우 통과가 됐습니다.

그런데 또 다른 문제가 생겼습니다. Gazebo 시뮬레이션에서 완벽하게 돌아가던 값이 실제 Pi 5에 올리니까 planner가 너무 느려서 로봇이 멈칫멈칫 거리는 겁니다. CPU가 버거워하는 거였죠. planner 주기를 10Hz에서 5Hz로 낮추고, BT server timeout도 500ms까지 늘려서야 안정적으로 동작했습니다.

거기에 실제 Map과 Gazebo World 간의 미세한 오차 때문에 시뮬레이션에서는 문제없던 경로가 실제 맵에서는 벽에 걸리는 경우도 있었습니다. 결국 다시 한번 더 실측하여 World를 실제 맵과 거의 동일하게 재구축했습니다.

이런 식으로 커밋 하나에 파라미터 한 줄 바꾸고, 테스트하고, 또 바꾸고를 수십 번 반복했습니다.

파라미터시뮬레이션실제 로봇 (Pi 5)이유
inflation_radius0.05 m0.01 m좁은 통로 통과를 위해 최소화
cost_scaling_factor1505.0벽 근처 경로 허용 범위 확대
robot_radius0.075 m0.075 m실제 로봇 크기 유지
planner_frequency10 Hz5 HzPi 5 CPU 부하 감소
bt_loop_duration10 ms500 msBT 서버 타임아웃 여유 확보
bond_timeout4 s30 slifecycle 노드 연결 안정화

ROS 2 Jazzy 호환성 문제도 꽤 골치 아팠습니다. collision_monitor의 파라미터 형식이 이전 버전과 달라져서, 처음에는 왜 노드가 안 뜨는지 한참을 헤맸습니다. 알고 보니 polygonsobservation_sources를 empty string_array로 명시해야 했고, docking_server config도 Jazzy에서는 필수로 요구되더군요. 이것만 해결하는 데 7~8번의 커밋이 필요했습니다.

수업 시간에는 로봇 한 대만 자율주행을 해봤기 때문에, 2대를 동시에 돌리는 건 처음이었습니다. 처음에 두 대를 동시에 켰더니 두 로봇이 같은 /cmd_vel 토픽에 명령을 쏘면서 서로의 모터를 제어하는 상황이 벌어졌습니다. 한 대가 전진하라고 하면 다른 한 대도 같이 전진하는 거죠.

예상은 했지만 이걸 해결하기 위해 namespace 격리를 적용했습니다. 각 로봇에 robot_54, robot_18이라는 namespace를 부여해서 토픽을 완전히 분리했습니다.

# 로봇별 독립 실행
ros2 launch shoppinkki_nav nav2_bringup.launch.py \
    namespace:=robot_54 \
    use_namespace:=true \
    robot_id:=54
 
ros2 launch shoppinkki_nav nav2_bringup.launch.py \
    namespace:=robot_18 \
    use_namespace:=true \
    robot_id:=18

그런데 namespace만 분리하면 끝날 줄 알았는데, 하나 해결하면 또 다른 문제가 튀어나왔습니다.

문제 원인 해결
토픽 충돌 두 로봇이 같은 /cmd_vel 발행 namespace로 /robot_54/cmd_vel, /robot_18/cmd_vel 분리
FastDDS 충돌 동일 노드 이름 → publisher 매칭 오류 로봇별 고유 노드 이름 부여
AMCL 초기 위치 Gazebo 좌표 ≠ map frame 좌표 map frame 기준으로 좌표 재계산
TF 프레임 충돌 base_link 이름 중복 namespace prefix 없이 TF 발행 (bringup이 자동 처리)

FastDDS에서는 노드 이름이 같으면 publisher가 꼬이는 문제가 있어서 고유 이름을 부여해야 했고, AMCL 초기 위치는 Gazebo world 좌표와 map frame 좌표가 달라서 실제 로봇이 엉뚱한 곳에 잡히는 문제도 있었습니다. 하나하나 해결해나가는 과정이었습니다.

복귀(RETURNING) 경로를 구현할 때 고민이 많았습니다. 단순히 "충전소 좌표로 가라 !"라고 하면 될 것 같지만, 실제로는 그렇게 간단하지 않았습니다. 결제를 마치고 출구 쪽에 있는 로봇이 다시 매장 안쪽을 가로질러서 충전소로 가면 동선이 엉망이 되거든요. 결제구역이나 출구로 나간 로봇은 다시 결제구역으로 돌아갈 수 없게 해야 했습니다.

그래서 로봇의 현재 위치에 따라 경로를 분기하는 방식을 택했습니다.

# 결제구역/출구 근처 판별 (좁은 세로 통로)
LOWER_AREA_THRESHOLD_Y = -1.2
LOWER_AREA_THRESHOLD_X = 0.3
 
in_lower_area = (cy < LOWER_AREA_THRESHOLD_Y
                 and cx < LOWER_AREA_THRESHOLD_X)
현재 위치조건경로
결제구역/출구 근처y < -1.2 且 x < 0.3현재 위치 → exit2 → 하단복도 → fleet 그래프 → 충전소
일반 매장 내부그 외현재 위치 → fleet 그래프 경로 → 충전소

결제구역이나 출구 근처는 Nav Graph 노드가 없는 좁은 세로 통로여서, 그래프 경로로는 갈 수가 없었습니다. 그래서 이 구간만 고정 경유점(exit2 → 하단복도)을 inflation OFF로 먼저 통과시키고, 하단복도부터 그래프 경로로 합류하는 방식으로 해결했습니다.

Admin UI · 플릿 그래프
결제구역1 하단_복도 출구2 출구1 P2 음료1 케이스 1 · 결제구역 출발 케이스 2 · 매장 내부 출발 충전소 (목적지)
실제 매장
결제구역 출구 하단복도 P1/P2 매장 내부
케이스 1 · 결제구역 / 출구 근처
현재 위치
──→ inflation OFF
exit2
0.0, -1.402
──→ inflation OFF
하단복도
0.0, -1.137
──→ inflation ON
fleet 경로
──→
충전소
케이스 2 · 일반 매장 내부
현재 위치
──→ inflation ON
fleet 그래프 경로
REST API 조회
──→
충전소

fleet 그래프 경로는 REST API로 control_service에 질의해서 받아옵니다. 중간 경유점의 theta는 다음 노드 방향으로 계산하고, 마지막 충전소 도착 시에는 저장된 주차 방향을 사용합니다.

# fleet 경로 질의
url = f"http://{host}:{port}/fleet/route?from_x={cx}&from_y={cy}&dest={charger_name}&robot_id={robot_id}"
route = requests.get(url).json()["route"]  # [{x, y}, ...]
 
# 중간점 theta = 다음 노드 방향, 마지막 theta = 충전소 저장 orientation
for i, pt in enumerate(route):
    if i == len(route) - 1:
        theta = slot["waypoint_theta"]     # 충전소 주차 방향
    else:
        theta = atan2(route[i+1].y - pt.y, route[i+1].x - pt.x)

충전소 슬롯은 2개(P1=140, P2=141)를 두어 빈 슬롯을 조회한 뒤 이동합니다.

2대의 로봇이 동시에 같은 코너로 이동하면 어떻게 될까? 이 문제를 해결하기 위해 처음에는 오픈소스 미들웨어인 Open-RMF를 도입했습니다. 대규모 로봇 Fleet을 관리하는 플랫폼이라 "이거면 해결되겠다" 싶었거든요.

적용엔 성공을 했습니다. 다만 상황이 달랐습니다. Open-RMF는 수십 대의 이기종 로봇을 전제로 만들어진 플랫폼이라, 고작 2대를 제어하는 데 노드 기동만 8초 이상 걸리고, Raspbery Pi 5에서만 돌아가는 우리 환경에는 조금 무거운 플랫폼이었습니다.

결국 Open-RMF에서 배운 Nav Graph 설정 방식은 그대로 가져가되, 런타임 의존성을 걷어내고 자체 Fleet Router를 직접 구현하기로 했습니다.

Open-RMF자체 Fleet Router
예약 차원시공간 — 궤적 + 시간축 (4D)공간 — 그래프 lane 선점
충돌 해결로봇 간 협상 프로토콜로 궤적 수정Dijkstra 페널티 가중치로 자동 우회
아키텍처분산 — Fleet Adapter + Schedule 노드중앙 집중 — FleetRouter 단일 노드
적합 규모대규모·이기종 Fleet2대 규모에 단순·충분

자체 Fleet Router에서는 3가지 유형의 충돌을 감지하고 처리합니다.

충돌 유형설명해결 방식
E_SHARE두 로봇이 같은 lane을 동시에 예약예약된 lane에 페널티 → Dijkstra 우회
E_OPPOSE두 로봇이 같은 lane을 반대 방향으로 진입우선순위 낮은 로봇이 holding point에서 대기
V_CONVERGE두 로봇이 같은 꼭짓점으로 수렴남은 웨이포인트 수로 양보 우선순위 결정

돌이켜보면, Open-RMF를 먼저 경험한 덕분에 Nav Graph 기반 경로 조율이 어떻게 동작하는지 이해할 수 있었고, 그 위에서 우리 규모에 맞는 단순한 솔루션을 설계할 수 있었습니다.

  • 협업이 잘 되었다 — 역할 분담이 명확했고, 덕분에 시스템 통합이 원활하게 진행되었습니다
  • 커스텀 YOLO + ReID + HSV 파이프라인이 예상보다 안정적으로 동작했습니다
  • ROS2 상태 머신 기반 아키텍처 덕분에 기능 간 충돌 없이 안정적인 전환이 가능했습니다
  • 멀티로봇 경로 조율 — 자체 Fleet Router로 2대의 로봇 간 경로 충돌을 해결하고, 순차 웨이포인트 내비게이션으로 안정적인 복귀 경로를 구현할 수 있었습니다

  • 음성 인식 미구현 — 텍스트 입력 대신 실제 음성으로 가이드를 요청하고 싶었습니다
  • 하드웨어 제약으로 실제 사람을 추종하는 것을 해보지 못했습니다
  • 구현하지 못한 시나리오들 — LOST 처리, LCD 표시, LED·부저 피드백, 실제 자동결제 구현 등

  • Open-RMF → 자체 구현 — 오픈소스를 적용해보고, 프로젝트 규모에 맞지 않는 부분을 판단하여 우리 프로젝트에 맞춰 직접 구현하는 경험을 했습니다. 의존성을 걷어내고 Fleet Router를 자체 구현하며 경로 조율의 복잡성을 체감했습니다
  • 하드웨어 제약 안에서의 설계 — 카메라와 연산의 한계를 소프트웨어로 극복하는 경험을 했습니다
  • 설계의 중요성 — 초반에 인터페이스와 아키텍처 설계에 투자한 시간이 후반 통합을 빠르게 만들어주었습니다

더 자세한 후기는 프로젝트 후기 블로그 글에서 확인할 수 있습니다.


🏗️ 시스템 아키텍처 클릭하여 펼치기 ▾

System Architecture

시스템은 UI / SERVER / EQUIP 세 개의 레이어로 구성됩니다.

레이어컴포넌트역할
UICustomer UI (스마트폰 브라우저)고객용 웹앱 — 상품 검색, 장바구니, 결제, 로봇 상태 확인
UIAdmin UI (관제 PC)PyQt 관리자 관제앱 — 로봇 모니터링, 알람, 강제 명령
SERVERCustomer Web (Flask + SocketIO)고객 UI 서빙 및 Control Service 중계
SERVERAI Server (Docker)YOLOv8 추론 서버 (TCP) + LLM 검색 서버 (REST)
SERVERControl Service (ROS2 + REST)로봇 명령·상태 관리, PostgreSQL DB 전담
EQUIPshoppinkki_core (Pi 5)상태머신 + 행동트리 통합 노드, HW 제어
EQUIPshoppinkki_nav (Pi 5)Nav2 BT (Guiding / Returning / Waiting 회피)
EQUIPshoppinkki_perception (Pi 5)YOLO 인형 감지 / QR 스캔

상세 문서: 시스템 아키텍처 · 인터페이스 명세

🔄 상태 머신 / FSM 클릭하여 펼치기 ▾

State Diagram

로봇은 10개 상태를 가지며, transitions 라이브러리 기반 FSM으로 전환을 관리합니다.

상태설명
CHARGING초기 상태, 충전 대기
IDLE사용자 등록 대기 (LCD에 QR 표시)
TRACKING주인 인형 추종 중
TRACKING_CHECKOUT결제 완료 후 추종 (출구 통과 허용)
GUIDINGNav2로 상품 위치 안내 이동
SEARCHING주인 놓침 → 제자리 회전 재탐색 (30초)
WAITING정지 대기, 통행자 감지 시 회피
LOCKED미결제 물건 있는 상태로 귀환
RETURNING충전소로 자율 복귀
HALTED배터리 부족 → 즉시 정지

상세 문서: 상태 머신 · 행동 트리 · 시나리오 목록

🗺️ Nav Graph 클릭하여 펼치기 ▾

Nav Graph

매장 내 로봇 이동 경로를 정의하는 28개 꼭짓점의 Nav Graph입니다. 충전소, 결제구역, 픽업존, 선반 우회점 등으로 구성되며 실좌표 기반으로 그리드 정렬되어 있습니다.

상세 문서: 매장 지도 설계

🗄️ ERD 클릭하여 펼치기 ▾

ERD

PostgreSQL 기반 중앙 DB로, USER / SESSION / CART / ROBOT / ZONE 등 11개 테이블로 구성됩니다.

상세 문서: ERD 설계


이름역할
박우림프로젝트 리딩 & 일정 관리, 전체 시스템 아키텍처 설계, 서버·로봇 통신 프레임워크, 상태 머신 & 행동 트리 설계, Gazebo 시뮬레이션 맵 제작
최민성매장 공간 설계 (CAD), 로봇 자율주행 기반 구축 (SLAM, Nav2), Open-RMF로 다중 로봇 경로 조율, 가이드 / 복귀 / 충전 자율주행
이정우커스텀 YOLOv8 학습, SAM3 마스크 생성, IoU 트래커 구현, ReID + HSV 추종 파이프라인, 장바구니 3D 프린팅
이강택실물 미니어처 매장 제작, 로그인·장바구니·대기 기능, QR 스캔 장바구니 관리, 결제 구역 감지 & 자동 결제 처리, Customer Web 맵 UI
이지수실물 미니어처 매장 제작, LLM 서버 구축 (Qwen 2.5 3B / Ollama), pgvector 자연어 구역 벡터 검색, 가이드 UI, LLM 답변 정확도 개선

프로젝트 발표(04.22) 이후에도 회고에서 아쉬웠던 부분들과 실제 운용 중 발견된 문제들을 지속적으로 개선했습니다.

회원가입 & 카드 관리 시스템 — 프로젝트 기간에는 사전 등록된 유저만 사용할 수 있었습니다. 회원가입 페이지와 API를 새로 구현하고, 결제 전 카드 미등록 시 등록 모달을 띄우도록 개선했습니다. 비밀번호는 bcrypt로 해싱하여 저장합니다.

관리자 유저/세션 관리 패널 — 기존 Admin UI에는 로봇 모니터링만 있었는데, 유저 목록 조회·삭제와 활성 세션 관리 기능을 추가했습니다. FK 제약 조건을 고려하여 유저 삭제 시 세션을 먼저 정리하는 로직도 함께 구현했습니다.

LED 상태 피드백 — 로봇의 상태머신 상태에 따라 WS2812B LED 스트립의 색상이 자동으로 변경되도록 구현했습니다. 충전(빨강), 대기(흰색), 추종(초록), 안내(노랑), 검색/대기(파랑), 복귀(보라), 미결제 잠금(빨강 깜빡임) 등 상태별 색상을 매핑하여 고객과 관리자가 로봇의 현재 상태를 직관적으로 파악할 수 있도록 했습니다.

영역 문제 수정 내용
Nav2 bt_navigator의 frame이 불일치하여 간헐적 TF 오류 발생 base_footprint으로 통일
Nav2 collision_monitor 노드 누락으로 다중 로봇 충돌 감지 불가 실제 로봇 launch에 노드 추가
상태 머신 GUIDING 중 Nav 실패 시 WAITING으로 빠져서 복구 불가 resume_tracking으로 추종 복귀
상태 머신 TRACKING/TRACKING_CHECKOUT에서 LOCKED 전환 불가 누락된 상태 전환 경로 추가
결제 checkout zone 경계가 웨이포인트(0.186)를 포함하지 않아 결제 미감지 x_max 범위 확장
HW 제어 LED·감정 표시 서비스 타입 오류로 로봇 피드백 미작동 올바른 서비스 타입으로 수정
배터리 저전압 감지 미구독으로 HALTED 전환 불가 battery/percent 토픽 구독 추가

  • XSS 방지 — Customer Web의 동적 값 innerHTML 삽입 시 이스케이프 처리 추가
  • SECRET_KEY 안전 생성 — 환경변수 미설정 시 랜덤 키 자동 생성
  • 로깅 표준화print()logger.info()로 전환하여 운영 로그 추적 가능
  • 설정 중앙화RETURN_RELAY_MODES, CHARGER_WAYPOINT_NAMES 등 하드코딩된 값을 config로 분리
  • 임시 파일 정리 — Nav2 파라미터 임시 파일이 프로세스 종료 시 자동 삭제되도록 개선