25.09.10 ~ 25.11.18 약 10주간 진행
Sprint1 : 주제 선정 / 기획 / 요구사항 정의
Sprint2~4 : 설계 / 기술조사
Sprint5 : 통신 구현
Sprint6~9 : 기능 구현 및 연동 테스트
Sprint10 : 발표 자료
| 분류 | 기술 |
|---|---|
| 개발환경 | |
| 언어 | |
| UI | |
| DBMS | |
| AI | |
| LLM | |
| 자율주행 | |
| 협업 |
원격 쇼핑 로봇을 주제로 선정한 이유
- AI의 발전
- 온라인 쇼핑 품질 불량 가능성
- 인터렉티브 콘텐츠
- 로봇 시장 성장
- 대형 마트와 소셜 커머스 경쟁
- 로봇과 커머스 융합 시장
등의 이유가 있겠습니다.
| UR_ID | Name | Description | Required | Remarks |
|---|---|---|---|---|
| UR_01 | 계정 관리 | 고객 계정 정보 관리 | R | 계정 정보: 이름, 성별, 나이, 배송 주소, 알레르기 정보, 이전 구매 내역 |
| UR_02 | 상품 탐색 | 상품 검색 및 추천 | R | - |
| UR_03 | 원격 쇼핑 | 원격 상품 선택 및 구매 | R | - |
| UR_04 | 원격 쇼핑 모니터링 | 실시간 쇼핑 현황 모니터링 | R | 로봇 위치, 이동 경로 및 ETA, 작업 상태(정지/이동/집기), 장바구니 상태, 전방 카메라 영상 |
| UR_ID | Name | Description | Required | Remarks |
|---|---|---|---|---|
| UR_05 | 상품 포장 보조 | 쇼핑 종료 후 상품 적재 및 정렬 | R | 정렬 기준: 손상 가능성 있는 물품 위로, 안전성 높은 방향 |
| UR_06 | 재고 보충 보조 | 직원 요청 시 창고 상품을 매대로 자율 운송 | O | - |
| UR_ID | Name | Description | Required | Remarks |
|---|---|---|---|---|
| UR_07 | 주문 정보 관리 | 주문 현황 확인 및 이력 조회 | R | 주문 정보: 주문 ID, 고객 ID, 상품 목록, 주문 상태 |
| UR_08 | 작업 정보 관리 | 작업 현황 확인 및 이력 조회 | R | 작업 정보: 작업 ID, 고객 ID, 로봇 ID, 작업 종류, 작업 상태 |
| UR_09 | 로봇 정보 관리 | 로봇 상태 확인 및 이력 조회 | R | 로봇 상태: 위치, 장바구니 상태, 배터리·충전, 오류 상태 |
| UR_10 | 상품 정보 관리 | 상품 정보 조회 및 수정 | R | 상품 ID, 바코드, 이름, 수량, 가격, 카테고리, 매대 위치, 알레르기/비건 여부 |
| UR_11 | 자율 복귀 | 작업 종료 후 스테이션 자동 복귀 | O | - |
| UR_12 | 자동 충전 | 로봇이 배터리 상태 판단 후 자동 충전 | O | - |
| UR_13 | 자율 주행 | 로봇이 목표 지점까지 자율 이동 | R | - |
사용자 요구사항을 크게 3가지로 요약하면,
'Shopee App (사용자 인터페이스) / Pickee (주행&상품선택) / Packee (상품포장)' 이렇게 요약할 수 있습니다.
| SR_ID | SR_NAME | Description | Priority | Remark |
|---|---|---|---|---|
| SR_01 | 로그인 | 고객 및 관리자가 로그인하는 기능 | R1 | 세부 기능: ID/비밀번호 인증 |
| SR_02 | 고객 정보 조회 | 고객 및 관리자가 고객 정보를 조회 | O | 조회 가능 정보: 이름, 성별, 나이, 알레르기 정보, 비건 유무, 이전 구매 내역 |
| SR_03 | 고객 정보 수정 | 고객/관리자가 고객 정보를 수정 | O | 수정 가능 정보: 알레르기 정보 업데이트, 비건 유무 업데이트 |
| SR_04 | 상품 검색 | 고객이 상품 정보를 검색 | R1 | 검색어 입력: 텍스트/음성, 조회 정보: 상품명/카테고리/가격/할인율/알레르기/비건 |
| SR_05 | 상품 추천 | 고객에게 상품 추천 제공 | O | 구매 이력 기반, 알레르기/비건 고려, 인기 상품 추천 |
| SR_06 | 상품 예약 | 고객이 상품을 예약 | R1 | 예약 상품 추가/삭제, 수량 변경, 예약 목록 조회 |
| SR_07 | 상품 결제 | 예약 상품 선결제 기능 | R1 | |
| SR_08 | 실시간 상품 선택 | 비기성품을 실시간으로 보고 선택 | R1 | 과일·육류 선택, 화면 클릭(bbox 클릭) |
| SR_09 | 장바구니 조회 | 장바구니 상품 조회 | R3 | |
| SR_10 | 실시간 영상 모니터링 | 로봇 카메라 영상 확인 | R2 | 전방 카메라, 로봇팔 카메라 |
| SR_11 | 쇼핑중 알림 | 특정 상황 발생 시 실시간 알림 | R3 | 매대 도착, 집기 시작/완료, 장애물 감지, 오류 |
| SR_12 | 장바구니 상태 확인 | 장바구니 현황 모니터링 | R4 | 담긴 상품 목록, 수량, 총액 |
| SR_13 | 상품 포장 보조 | 쇼핑 후 상품을 포장 박스로 적재 | R1 | 포장대 이동, 장바구니 인식, 포장 순서 계획, 듀얼암 적재, 포장 완료 검증 |
| SR_14 | 재고 보충 보조 | 로봇이 직원을 추종하며 보충 작업 지원 | O | 직원 추종, 음성 명령, 창고-매대 운반 |
| SR_15 | 주문 정보 조회 | 주문 정보 조회 | R1 | 주문 ID, 고객 ID, 상품 목록, 금액, 상태(PAID 등), 주문 시간 |
| SR_16 | 주문 이력 조회 | 주문 이력 조회 | R2 | 주문 ID/고객 ID, 주문 일시, 상품 목록, 금액, 최종 상태 |
| SR_17 | 작업 정보 모니터링 | 모든 작업 정보/상태 모니터링 | R1 | 작업 ID, 고객/로봇 ID, 작업 종류, 상태, 시간 |
| SR_18 | 작업 이력 조회 | 작업 이력 조회 | R2 | 작업 ID, 로봇/고객 ID, 상태, 실패 이유, 위치, 시간 |
| SR_19 | 로봇 상태 조회 | 로봇 상태 실시간 조회 | R1 | 로봇 ID/타입, 위치, 장바구니 상태, 배터리, 오류, 작업 ID |
| SR_20 | 로봇 이력 조회 | 로봇 상태 이력 조회 | R2 | 위치 이동, 작업 수행, 충전, 오류, 상태 변경 timestamp |
| SR_21 | 상품 정보 조회 | 상품 정보를 조회 | R3 | 상품 ID, 바코드, 이름, 카테고리, 재고, 가격, 매대 위치, 알레르기/비건 |
| SR_22 | 상품 정보 수정 | 상품 정보를 수정 | R3 | 상품 추가/삭제, 바코드/이름 수정, 재고·가격 수정, 매대 위치, 알레르기 정보 |
| SR_23 | 로봇 자동 복귀 | 작업 종료 시 자동 복귀/다음 미션 이동 | ||
| SR_24 | 로봇 자동 충전 | 배터리 상태 기반 자동 충전 | R4 | |
| SR_25 | 장애물 회피 | 경로 중 장애물 감지·회피 경로 생성 | R1 | 정적: 카트/박스, 동적: 사람/모바일 로봇 |
SC05: 관리자 기능
SC-05-01: 관리자 모니터링로봇 정보 표시
로봇 위치 표시
로봇 시야 확인
로봇 시야 송출 종료
로봇 상태 조회
진행율 확인
SC-05-02: 관리자 재고 관리
재고 정보 조회
재고 정보 수정
재고 정보 추가
재고 정보 삭제
SC-05-03: 관리자 작업 이력 조회
SC06: 직원 보조 기능
SC-06-01: 모드 시작SC-06-02: 인식 및 추종
SC-06-03: 음성 명령
SC-06-04: 목적지 이동
SC-06-05: 임무 완료 확인
TCP 통신
| Function | From | To | Message Type | Schema |
|---|---|---|---|---|
| 사용자 로그인 요청 | App | Main Service | user_login | json { "type": "user_login", "data": { "user_id": "string", "password": "string" } } |
| 사용자 로그인 응답 | Main Service | App | user_login_response | json { "type": "user_login_response", "result": true, "error_code": "string", "data": { "user_id": "string", "name": "string", "gender": "boolean", "age": "int", "address": "string", "allergy_info": { "nuts": "boolean", "milk": "boolean", "seafood": "boolean", "soy": "boolean", "peach": "boolean", "gluten": "boolean", "eggs": "boolean" }, "is_vegan": "boolean" }, "message": "string" } |
| 유저 정보 수정 요청 | App | Main Service | user_edit | json { "type": "user_edit", "result": true, "error_code": "string", "data": { "user_id": "string", "name": "string", "gender": "boolean", "age": "int", "address": "string", "allergy_info": { "nuts": "boolean", "milk": "boolean", "seafood": "boolean", "soy": "boolean", "peach": "boolean", "gluten": "boolean", "eggs": "boolean" }, "is_vegan": "boolean" } } |
| 유저 정보 수정 응답 | Main Service | App | user_edit_response | json { "type": "user_edit_response", "result": true, "error_code": "string", "data": { "user_id": "string", "name": "string", "gender": "boolean", "age": "int", "address": "string", "allergy_info": { "nuts": "boolean", "milk": "boolean", "seafood": "boolean", "soy": "boolean", "peach": "boolean", "gluten": "boolean", "eggs": "boolean" }, "is_vegan": "boolean" }, "message": "string" } |
| 전체 상품 요청 | App | Main Service | total_product | json { "type": "total_product", "data": { "user_id": "string" } } |
| 전체 상품 응답 | Main Service | App | total_product_response | json { "type": "total_product_response", "result": true, "error_code": "string", "data": { "products": [ { "product_id": "int", "name": "string", "price": "int", "discount_rate": "int", "category": "string", "allergy_info": { "nuts": "boolean", "milk": "boolean", "seafood": "boolean", "soy": "boolean", "peach": "boolean", "gluten": "boolean", "eggs": "boolean" }, "is_vegan_friendly": "boolean" } ], "total_count": "int" }, "message": "string" } |
| 상품 검색 요청 | App | Main Service | product_search | json { "type": "product_search", "data": { "user_id": "string", "query": "string", "filter": { "allergy_info": { "nuts": "boolean", "milk": "boolean", "seafood": "boolean", "soy": "boolean", "peach": "boolean", "gluten": "boolean", "eggs": "boolean" }, "is_vegan": "boolean" } } } |
| 상품 검색 응답 | Main Service | App | product_search_response | json { "type": "product_search_response", "result": true, "error_code": "string", "data": { "products": [ { "product_id": "int", "name": "string", "price": "int", "quantity": "int", "section_id": "int", "category": "string", "allergy_info_id": "int", "is_vegan_friendly": "boolean" } ], "total_count": "int" }, "message": "string" } |
| 주문 생성 요청 | App | Main Service | order_create | json { "type": "order_create", "data": { "user_id": "string", "cart_items": [ { "product_id": "int", "quantity": "int" } ], "payment_method": "string", "total_amount": "int" } } |
| 주문 생성 응답 | Main Service | App | order_create_response | json { "type": "order_create_response", "result": true, "error_code": "string", "data": { "order_id": "int", "robot_id": "int", "products": [ { "product_id": "int", "name": "string", "quantity": "int", "auto_select": "boolean" } ], "total_count": "int" }, "message": "string" } |
| 상품 선택 요청 | App | Main Service | product_selection | json { "type": "product_selection", "data": { "order_id": "int", "robot_id": "int", "bbox_number": "int", "product_id": "int" } } |
| 상품 선택 응답 | Main Service | App | product_selection_response | json { "type": "product_selection_response", "result": true, "error_code": "string", "data": { "order_id": "int", "product_id": "int", "bbox_number": "int" }, "message": "string" } |
| 상품 선택 요청 (텍스트) | App | Main Service | product_selection_by_text | json { "type": "product_selection_by_text", "data": { "order_id": "int", "robot_id": "int", "speech": "string" } } |
| 상품 선택 응답 (텍스트) | Main Service | App | product_selection_by_text_response | json { "type": "product_selection_by_text_response", "result": true, "error_code": "string", "data": { "bbox": "int", "product_id": "int" }, "message": "string" } |
| 쇼핑 종료 요청 | App | Main Service | shopping_end | json { "type": "shopping_end", "data": { "user_id": "string", "order_id": "int" } } |
| 쇼핑 종료 응답 | Main Service | App | shopping_end_response | json { "type": "shopping_end_response", "result": true, "error_code": "string", "data": { "order_id": "int", "total_items": "int", "total_price": "int" }, "message": "string" } |
| 영상 스트림 시작 요청 | App | Main Service | video_stream_start | json { "type": "video_stream_start", "data": { "user_type": "string", "user_id": "string", "robot_id": "int", "camera_type": "string" } } |
| 영상 스트림 시작 응답 | Main Service | App | video_stream_start_response | json { "type": "video_stream_start_response", "result": true, "error_code": "string", "data": {}, "message": "string" } |
| 영상 스트림 중지 요청 | App | Main Service | video_stream_stop | json { "type": "video_stream_stop", "data": { "user_type": "string", "user_id": "string", "robot_id": "int" } } |
| 영상 스트림 중지 응답 | Main Service | App | video_stream_stop_response | json { "type": "video_stream_stop_response", "result": true, "error_code": "string", "data": {}, "message": "string" } |
| 재고 조회 요청 | App | Main Service | inventory_search | ```json { "type": "inventory_search", "data": { "product_id": "int |
| 재고 조회 응답 | Main Service | App | inventory_search_response | json { "type": "inventory_search_response", "result": true, "error_code": "string", "data": { "products": [ { "product_id": "int", "barcode": "string", "name": "string", "quantity": "int", "price": "int", "section_id": "int", "category": "string", "allergy_info_id": "int", "is_vegan_friendly": "boolean" } ], "total_count": "int" }, "message": "string" } |
| 재고 추가 요청 | App | Main Service | inventory_create | json { "type": "inventory_create", "data": { "product_id": "int", "barcode": "string", "name": "string", "quantity": "int", "price": "int", "section_id": "int", "category": "string", "allergy_info_id": "int", "is_vegan_friendly": "boolean" } } |
| 재고 추가 응답 | Main Service | App | inventory_create_response | json { "type": "inventory_create_response", "result": true, "error_code": "string", "data": {}, "message": "string" } |
| 재고 수정 요청 | App | Main Service | inventory_update | json { "type": "inventory_update", "data": { "product_id": "int", "barcode": "string", "name": "string", "quantity": "int", "price": "int", "section_id": "int", "category": "string", "allergy_info_id": "int", "is_vegan_friendly": "boolean" } } |
| 재고 수정 응답 | Main Service | App | inventory_update_response | json { "type": "inventory_update_response", "result": true, "error_code": "string", "data": {}, "message": "string" } |
| 재고 삭제 요청 | App | Main Service | inventory_delete | json { "type": "inventory_delete", "data": { "product_id": "int" } } |
| 재고 삭제 응답 | Main Service | App | inventory_delete_response | json { "type": "inventory_delete_response", "result": true, "error_code": "string", "data": {}, "message": "string" } |
| 작업 이력 조회 요청 | App | Main Service | robot_history_search | ```json { "type": "robot_history_search", "data": { "robot_history_id": "int |
| 작업 이력 조회 응답 | Main Service | App | robot_history_search_response | ```json { "type": "robot_history_search_response", "result": true, "error_code": "string", "data": { "histories": [ { "robot_history_id": "int", "robot_id": "int", "order_item_id": "int |
| 로봇 상태 조회 요청 | App | Main Service | robot_status_request | ```json { "type": "robot_status_request", "data": { "robot_type": "string |
| 로봇 상태 조회 응답 | Main Service | App | robot_status_response | ```json { "type": "robot_status_response", "result": true, "error_code": "string", "data": { "robots": [ { "robot_id": "int", "type": "string", "status": "string", "detailed_status": "string", "reserved": "boolean", "active_order_id": "int |
| 로봇 유지보수 모드 설정 요청 | App | Main Service | robot_maintenance_mode | json { "type": "robot_maintenance_mode", "data": { "robot_id": "int", "enabled": "boolean" } } |
| 로봇 유지보수 모드 설정 응답 | Main Service | App | robot_maintenance_mode_response | json { "type": "robot_maintenance_mode_response", "result": true, "error_code": "string", "data": { "robot_id": "int", "maintenance_mode": "boolean" }, "message": "string" } |
| 서비스 헬스체크 요청 | App | Main Service | health_check | json { "type": "health_check" } |
| 서비스 헬스체크 응답 | Main Service | App | health_check_response | json { "type": "health_check_response", "result": true, "error_code": "string", "data": { "status": "string", "checks": { "database": "boolean", "ros2": "boolean", "robot_count": "int" } }, "message": "string" } |
| 로봇 이동 알림 | Main Service | App | robot_moving_notification | json { "type": "robot_moving_notification", "result": true, "error_code": "string", "data": { "order_id": "int", "robot_id": "int", "destination": "string" }, "message": "string" } |
| 로봇 도착 알림 | Main Service | App | robot_arrived_notification | json { "type": "robot_arrived_notification", "result": true, "error_code": "string", "data": { "order_id": "int", "robot_id": "int", "location_id": "int", "section_id": "int" }, "message": "string" } |
| 상품 담기 완료 알림 | Main Service | App | picking_complete_notification | json { "type": "picking_complete_notification", "result": true, "error_code": "string", "data": { "order_id": "int", "robot_id": "int" }, "message": "string" } |
| 상품 선택 시작 알림 | Main Service | App | product_selection_start | json { "type": "product_selection_start", "result": true, "error_code": "string", "data": { "order_id": "int", "robot_id": "int", "products": [ { "product_id": "int", "name": "string", "bbox_number": "int" } ] }, "message": "string" } |
| 장바구니 담기 알림 | Main Service | App | cart_update_notification | json { "type": "cart_update_notification", "result": true, "error_code": "string", "data": { "order_id": "int", "robot_id": "int", "action": "string", "product": { "product_id": "int", "name": "string", "quantity": "int", "price": "int" }, "total_items": "int", "total_price": "int" }, "message": "string" } |
| 작업 정보 알림 | Main Service | App | work_info_notification | json { "type": "work_info_notification", "result": true, "error_code": "string", "data": { "robot_id": "int", "destination": "string", "progress": "int", "active_duration": "int", "user_id": "string", "customer_name": "string", "customer_allergy_info_id": "int", "customer_is_vegan": "boolean" }, "message": "string" } |
| 포장 정보 알림 | Main Service | App | packing_info_notification | json { "type": "packing_info_notification", "result": true, "error_code": "string", "data": { "order_status": "string", "product_id": "int", "product_name": "string", "product_price": "int", "product_quantity": "int" }, "message": "string" } |
UDP 통신
| 항목 | 내용 |
|---|---|
| Port | 6000 |
| Protocol | UDP |
| Data Format | JSON (메타데이터) + Binary (이미지 데이터) |
| Max Packet Size | 1,600 bytes (1,400 bytes data + 200 bytes header) |
| Encoding | UTF-8 (JSON), Binary (Image) |
| Image Format | JPEG |
| Resolution | 640×480 |
| Frame Delivery Type | Chunk-based Transmission (Partial Segmentation) |
[ JSON Header (≈200 bytes) ] + [ Binary Image Data (max 1,400 bytes) ]
{
"type": "video_frame",
"robot_id": 1,
"frame_id": 12345,
"chunk_idx": 0,
"total_chunks": 50,
"data_size": 1400,
"timestamp": 1730000000000,
"width": 640,
"height": 480,
"format": "jpeg"
}
Main -> App
| Function | From | To | Message Type | 상세 메시지 포맷 | 비고 |
|---|---|---|---|---|---|
| 영상 송출 | Main Service | App | video_frame | { "type": "video_frame", "robot_id": 1, "frame_id": 12345, "chunk_idx": 0, "total_chunks": 50, "data_size": 1400, "timestamp": 1730000000000, "width": 640, "height": 480, "format": "jpeg" } + Binary Data (max 1,400 bytes) |
640x480 JPEG 분할 전송 |
Pic Vision -> Main
| Function | From | To | Message Type | 상세 메시지 포맷 | 비고 |
|---|---|---|---|---|---|
| 영상 송출 | Pic Vision | Main | video_frame | { "type": "video_frame", "robot_id": 1, "frame_id": 12345, "chunk_idx": 0, "total_chunks": 50, "data_size": 1400, "timestamp": 1730000000000, "width": 640, "height": 480, "format": "jpeg" } + Binary Data (max 1,400 bytes) |
640x480 JPEG 분할 전송 |
HTTP 통신
Service Name: Shopee LLM Service
Clients: Shopee Main Service, Pickee Main Controller
Port: 5001
Protocol: HTTP (RESTful)
| 코드 (status_code) | 요청 결과 |
|---|---|
| 200 | 정상 요청, 데이터 응답 성공 |
| 400 | 잘못된 요청 (Bad Request) |
| 401 | 정상 요청, 정보 없음 또는 응답 실패 |
| 404 | 잘못된 요청 (Not Found) |
| 405 | 메소드가 리소스에서 허용되지 않음 |
| 500 | 서버 내부 오류 |
| 503 | 서비스 불가 |
| Function | Endpoint | Request | Response |
|---|---|---|---|
| 상품 검색 쿼리 생성 | GET /llm/search_query | { "text": "사과 정보 알려줘" } |
{ "sql_query": "name LIKE '%사과%'" } |
| bbox 번호 추출 | GET /llm/bbox | { "text": "2번 집어줘" } |
{ "bbox": 2 } |
| 발화 의도 분석 | GET /llm/intent_detection | { "text": "피키야, XX로 이동해줘" } |
{ "intent": "Move_place", "entities": { "place_name": "XX", "action": "move" } } |
ROS2 통신
🔹 Publish / Subscribe 메시지 (Message)
| Function | Topic | Message Type | From | To | 상세 메시지 포맷 |
|---|---|---|---|---|---|
| 이동 시작 알림 | /pickee/moving_status | shopee_interfaces/msg/PickeeMoveStatus.msg | Pic Main | Main | int32 robot_id int32 order_id int32 location_id |
| 도착 보고 | /pickee/arrival_notice | shopee_interfaces/msg/PickeeArrival.msg | Pic Main | Main | int32 robot_id int32 order_id int32 location_id int32 section_id |
| 상품 위치 인식 완료 | /pickee/product_detected | shopee_interfaces/msg/PickeeProductDetection.msg | Pic Main | Main | int32 robot_id int32 order_id DetectedProduct[] products |
| 장바구니 교체 완료 | /pickee/cart_handover_complete | shopee_interfaces/msg/PickeeCartHandover.msg | Pic Main | Main | int32 robot_id int32 order_id |
| 로봇 상태 전송 | /pickee/robot_status | shopee_interfaces/msg/PickeeRobotStatus.msg | Pic Main | Main | int32 robot_id string state float32 battery_level int32 current_order_id float32 position_x float32 position_y float32 orientation_z |
| 담기 완료 보고 | /pickee/product/selection_result | shopee_interfaces/msg/PickeeProductSelection.msg | Pic Main | Main | int32 robot_id int32 order_id int32 product_id bool success int32 quantity string message |
| 창고 물품 적재 완료 | /pickee/product/loaded | shopee_interfaces/msg/PickeeProductLoaded.msg | Pic Main | Main | int32 robot_id int32 product_id int32 quantity bool success string message |
🔹 메시지 구조 상세 (DetectedProduct 등)
DetectedProduct
- int32 product_id
- float32 confidence
- BBox bbox
- int32 bbox_number
- DetectionInfo detection_info
- Point3D position
DetectionInfo
- Point2D[] polygon
- BBox bbox_coords
Point2D
- float32 x
- float32 y
BBox
- int32 x1
- int32 y1
- int32 x2
- int32 y2
🔹 Service 호출 표
| Function | Service Name | Service Type | From | To | 상세 메시지 |
|---|---|---|---|---|---|
| 작업 시작 명령 | /pickee/workflow/start_task | shopee_interfaces/srv/PickeeWorkflowStartTask.srv | Main | Pic Main | Request int32 robot_id int32 order_id string user_id ProductLocation[] product_list Response bool success string message |
| 섹션 이동 명령 | /pickee/workflow/move_to_section | shopee_interfaces/srv/PickeeWorkflowMoveToSection.srv | Main | Pic Main | Request: robot_id, order_id, location_id, section_id Response: success, message |
| 상품 인식 명령 | /pickee/product/detect | shopee_interfaces/srv/PickeeProductDetect.srv | Main | Pic Main | Request: robot_id, order_id, int32[] product_ids Response: success, message |
| 상품 담기 명령 | /pickee/product/process_selection | shopee_interfaces/srv/PickeeProductProcessSelection.srv | Main | Pic Main | Request: robot_id, order_id, product_id, bbox_number Response: success, message |
| 쇼핑 종료 명령 | /pickee/workflow/end_shopping | shopee_interfaces/srv/PickeeWorkflowEndShopping.srv | Main | Pic Main | Request: robot_id, order_id Response: success, message |
| 포장대 이동 명령 | /pickee/workflow/move_to_packaging | shopee_interfaces/srv/PickeeWorkflowMoveToPackaging.srv | Main | Pic Main | Request: robot_id, order_id, location_id Response: success, message |
| 복귀 명령 | /pickee/workflow/return_to_base | shopee_interfaces/srv/PickeeWorkflowReturnToBase.srv | Main | Pic Main | Request: robot_id, location_id Response: success, message |
| 직원으로 복귀 명령 | /pickee/workflow/return_to_staff | shopee_interfaces/srv/PickeeWorkflowReturnToStaff.srv | Main | Pic Main | Request: robot_id Response: success, message |
| 영상 송출 시작 | /pickee/video_stream/start | shopee_interfaces/srv/PickeeMainVideoStreamStart.srv | Main | Pic Main | Request: user_type, user_id, robot_id, camera_type Response: success, message |
| 영상 송출 중지 | /pickee/video_stream/stop | shopee_interfaces/srv/PickeeMainVideoStreamStop.srv | Main | Pic Main | Request: user_type, user_id, robot_id Response: success, message |
| 상품 위치 조회 | /main/get_product_location | shopee_interfaces/srv/MainGetProductLocation.srv | Pic Main | Main | Request: product_id Response: success, warehouse_id, section_id, message |
| 좌표 정보 조회 | /main/get_location_pose | shopee_interfaces/srv/MainGetLocationPose.srv | Pic Main | Main | Request: location_id Response: Pose2D pose, success, message |
| 창고 좌표 조회 | /main/get_warehouse_pose | shopee_interfaces/srv/MainGetWarehousePose.srv | Pic Main | Main | Request: warehouse_id Response: Pose2D pose, success, message |
| 섹션 좌표 조회 | /main/get_section_pose | shopee_interfaces/srv/MainGetSectionPose.srv | Pic Main | Main | Request: section_id Response: Pose2D pose, success, message |
Pose2D
- float32 x
- float32 y
- float32 theta
🟦 1. 메시지(Message) 표
| Function(기능) | Topic | Message Type | From | To | 메시지 필드 |
|---|---|---|---|---|---|
| 매대 상품 인식 완료 | /pickee/vision/detection_result | shopee_interfaces/msg/PickeeVisionDetection.msg | Pic Vision | Pic Main | int32 robot_id int32 order_id bool success DetectedProduct[] products string message |
| 장바구니 상품 확인 완료 | /pickee/vision/cart_check_result | shopee_interfaces/msg/PickeeVisionCartCheck.msg | Pic Vision | Pic Main | int32 robot_id int32 order_id bool success int32 product_id bool found int32 quantity string message |
| 장애물 감지 알림 | /pickee/vision/obstacle_detected | shopee_interfaces/msg/PickeeVisionObstacles.msg | Pic Vision | Pic Main | int32 robot_id int32 order_id Obstacle[] obstacles string message |
| 직원 위치 추종 정보 | /pickee/vision/staff_location | shopee_interfaces/msg/PickeeVisionStaffLocation.msg | Pic Vision | Pic Main | int32 robot_id Point2D relative_position float32 distance bool is_tracking |
| 직원 등록 결과 | /pickee/vision/register_staff_result | shopee_interfaces/msg/PickeeVisionStaffRegister.msg | Pic Vision | Pic Main | int32 robot_id bool success string message |
🟦 1-1. 메시지 구조 상세
🔸 DetectedProduct 구조
DetectedProduct
- int32 product_id
- float32 confidence
- BBox bbox
- int32 bbox_number
- DetectionInfo detection_info
- Pose6D pose
DetectionInfo
- Point2D[] polygon
- BBox bbox_coords
🔸 Obstacle 구조
Obstacle
- string obstacle_type # cart, box, product, shelf, person, other_robot, cart_moving
- Point2D position # (m)
- float32 distance
- float32 velocity
- Vector2D direction
- BBox bbox
- float32 confidence
🔸 공통 구조체
Point2D: float32 x, float32 y
Vector2D: float32 vx, float32 vy
BBox: int32 x1, y1, x2, y2
🟩 2. 서비스(Service) 표
| Function(기능) | Service Name | Service Type | From | To | 요청/응답 |
|---|---|---|---|---|---|
| 매대 상품 인식 요청 | /pickee/vision/detect_products | shopee_interfaces/srv/PickeeVisionDetectProducts.srv | Pic Main | Pic Vision | Request: robot_id, order_id, int32[] product_ids Response: success, message |
| 장바구니 특정 상품 확인 | /pickee/vision/check_product_in_cart | shopee_interfaces/srv/PickeeVisionCheckProductInCart.srv | Pic Main | Pic Vision | Request: robot_id, order_id, product_id Response: success, message |
| 장바구니 존재 확인 | /pickee/vision/check_cart_presence | shopee_interfaces/srv/PickeeVisionCheckCartPresence.srv | Pic Main | Pic Vision | Request: robot_id, order_id Response: success, bool cart_present, float confidence, message |
| 영상 송출 시작 | /pickee/vision/video_stream_start | shopee_interfaces/srv/PickeeVisionVideoStreamStart.srv | Pic Main | Pic Vision | Request: user_type, user_id, robot_id, camera_type Response: success, message |
| 영상 송출 중지 | /pickee/vision/video_stream_stop | shopee_interfaces/srv/PickeeVisionVideoStreamStop.srv | Pic Main | Pic Vision | Request: user_type, user_id, robot_id Response: success, message |
| 직원 등록 요청 | /pickee/vision/register_staff | shopee_interfaces/srv/PickeeVisionRegisterStaff.srv | Pic Main | Pic Vision | Request: robot_id Response: accepted, message |
| 직원 추종 제어 | /pickee/vision/track_staff | shopee_interfaces/srv/PickeeVisionTrackStaff.srv | Pic Main | Pic Vision | Request: robot_id, bool track Response: success, message |
| Vision 모드 변경 | /pickee/vision/set_mode | shopee_interfaces/srv/PickeeVisionSetMode.srv | Pic Main | Pic Vision | Request: robot_id, string mode Response: success, message |
| 음성 출력 요청 | /pickee/tts_request | shopee_interfaces/srv/PickeeTtsRequest.srv | Pic Vision | Pic Main | Request: robot_id, text_to_speak Response: success, message |
🔹 Vision Mode 종류
idle
navigation
register_staff
detect_products
track_staff
| 기능 | 토픽명 | 메시지 타입 | 송신 | 수신 | 주요 필드 및 설명 |
|---|---|---|---|---|---|
| 자세 변경 상태 | /pickee/arm/pose_status | shopee_interfaces/msg/ArmPoseStatus.msg | Pic Arm | Pic Main |
|
| 픽업 상태 | /pickee/arm/pick_status | shopee_interfaces/msg/ArmTaskStatus.msg | Pic Arm | Pic Main |
|
| 담기 상태 | /pickee/arm/place_status | shopee_interfaces/msg/ArmTaskStatus.msg | Pic Arm | Pic Main |
|
| 기능 | 서비스명 | 서비스 타입 | 송신 | 수신 | 요청(Request) 필드 | 응답(Response) 필드 | 비고 |
|---|---|---|---|---|---|---|---|
| 자세 변경 요청 | /pickee/arm/move_to_pose | shopee_interfaces/srv/ArmMoveToPose.srv | Pic Main | Pic Arm | int32 robot_id int32 order_id string pose_type ("shelf_view", "cart_view", "standby") |
bool success string message |
|
| 상품 확인 요청 | /pickee/arm/check_product | shopee_interfaces/srv/ArmCheckBbox.srv | Pic Main | Pic Arm | int32 bbox_number | bool success string message |
|
| 상품 담기 요청 | /pickee/arm/place_product | shopee_interfaces/srv/ArmPlaceProduct.srv | Pic Main | Pic Arm | int32 robot_id int32 order_id int32 product_id string arm_side (Pickee는 "") Pose6D pose |
bool success string message |
| 필드명 | 타입 | 설명 |
|---|---|---|
| x | float32 | 위치 x |
| y | float32 | 위치 y |
| z | float32 | 위치 z |
| rx | float32 | 회전 x |
| ry | float32 | 회전 y |
| rz | float32 | 회전 z |
| 기능 | 토픽명 | 메시지 타입 | 송신 | 수신 | 주요 필드 및 설명 |
|---|---|---|---|---|---|
| 위치 업데이트 | /pickee/mobile/pose | shopee_interfaces/msg/PickeeMobilePose.msg | Pic Mobile | Pic Main |
|
| 도착 알림 | /pickee/mobile/arrival | shopee_interfaces/msg/PickeeMobileArrival.msg | Pic Mobile | Pic Main |
|
| 상태 알림 | /pickee/mobile/status | shopee_interfaces/msg/PickeeMobileStatus | Pic Mobile | Pic Main |
|
| 속도 제어 | /pickee/mobile/speed_control | shopee_interfaces/msg/PickeeMobileSpeedControl.msg | Pic Main | Pic Mobile |
|
| 도킹 - 목적지 아르코 마커 정보 | /pickee/mobile/aruco_pose | shopee_interfaces/msg/ArucoPose.msg | Pic Main | Pic Mobile |
|
| 도킹 - 도킹 완료 알림 | /pickee/mobile/docking_result | std_msgs/msg/Bool | Pic Mobile | Pic Main |
|
| 사람 트래킹 | /pickee/mobile/person_detection | shopee_interfaces/msg/PersonDetection.msg | Pic Main | Pic Mobile |
|
| 기능 | 서비스명 | 서비스 타입 | 송신 | 수신 | 요청(Request) 필드 | 응답(Response) 필드 |
|---|---|---|---|---|---|---|
| 목적지 이동 명령 | /pickee/mobile/move_to_location | shopee_interfaces/srv/PickeeMobileMoveToLocation.srv | Pic Main | Pic Mobile | int32 robot_id int32 order_id int32 location_id shopee_interfaces/msg/Pose2D target_pose |
bool success string message |
| 목적지 변경 | /pickee/mobile/update_global_path | shopee_interfaces/srv/PickeeMobileUpdateGlobalPath.srv | Pic Main | Pic Mobile | int32 robot_id int32 order_id int32 location_id shopee_interfaces/msg/Pose2D target_pose |
bool success string message |
| 트래킹 모드 변경 | /pickee/mobile/change_tracking_mode | shopee_interfaces/srv/ChangeTrackingMode.srv | Pic Main | Pic Mobile | int32 robot_id string mode |
bool success string message |
- **shopee_interfaces/msg/Pose2D**
- float32 x
- float32 y
- float32 theta
- **shopee_interfaces/msg/Obstacle**
- (InterfaceSpecification 문서 참고)
- **shopee_interfaces/msg/ArucoPose**
- int32 aruco_id
- float32 x, y, z
- float32 roll, pitch, yaw
- **shopee_interfaces/msg/PersonDetection**
- int32 robot_id
- string direction
| 기능 | 토픽명 | 메시지 타입 | 송신 | 수신 | 주요 필드 및 설명 |
|---|---|---|---|---|---|
| 포장 완료 알림 | /packee/packing_complete | shopee_interfaces/msg/PackeePackingComplete.msg | Pac Main | Main |
|
| 로봇 상태 전송 | /packee/robot_status | shopee_interfaces/msg/PackeeRobotStatus.msg | Pac Main | Main |
|
| 작업 가능 확인 완료 | /packee/availability_result | shopee_interfaces/msg/PackeeAvailability.msg | Pac Main | Main |
available: 로봇 상태 기준 cart_detected: 비전 기반 감지 결과 |
| 기능 | 서비스명 | 서비스 타입 | 송신 | 수신 | 요청(Request) 필드 | 응답(Response) 필드 |
|---|---|---|---|---|---|---|
| 작업 가능 확인 요청 | /packee/packing/check_availability | shopee_interfaces/srv/PackeePackingCheckAvailability.srv | Main | Pac Main | int32 robot_id int32 order_id |
bool success string message |
| 포장 시작 명령 | /packee/packing/start | shopee_interfaces/srv/PackeePackingStart.srv | Main | Pac Main | int32 robot_id int32 order_id shopee_interfaces/ProductInfo[] products |
int32 box_id bool success string message |
| 필드명 | 타입 | 설명 |
|---|---|---|
| product_id | int32 | 상품 ID |
| quantity | int32 | 수량 |
| length | int32 | 길이(mm) |
| width | int32 | 폭(mm) |
| height | int32 | 높이(mm) |
| weight | int32 | 무게(g) |
| fragile | bool | 파손주의 여부 |
| 기능 | 서비스명 | 서비스 타입 | 송신 | 수신 | 요청(Request) 필드 | 응답(Response) 필드 |
|---|---|---|---|---|---|---|
| 장바구니 유무 확인 | /packee/vision/check_cart_presence | shopee_interfaces/srv/VisionCheckCartPresence.srv | Pac Main | Pac Vision | int32 robot_id int32 order_id |
bool success bool cart_present float32 confidence string message |
| 장바구니 내 상품 위치 확인 | /packee/vision/detect_products_in_cart | shopee_interfaces/srv/PackeeVisionDetectProductsInCart.srv | Pac Main | Pac Vision | int32 robot_id int32 order_id int32[] expected_product_ids |
bool success shopee_interfaces/msg/DetectedProduct[] products int32 total_detected string message |
| 포장 완료 확인 | /packee/vision/verify_packing_complete | shopee_interfaces/srv/PackeeVisionVerifyPackingComplete.srv | Pac Main | Pac Vision | int32 robot_id int32 order_id |
bool cart_empty int32 remaining_items int32[] remaining_product_ids string message |
| bpp 알고리즘 시작 | /packee/vision/bpp_start | shopee_interfaces/srv/PackeeVisionBppStart | Pac Main | Pac Vision | int32 robot_id int32 order_id shopee_interfaces/ProductInfo[] products |
bool success string message |
| bpp 알고리즘 완료 | /packee/vision/bpp_complete | shopee_interfaces/srv/PackeeMainStartMTC | Pac Vision | Pac Main | int32 robot_id int32 order_id shopee_interfaces/Sequence[] sequences |
bool success string message |
| 필드명 | 타입 | 설명 |
|---|---|---|
| product_id | int32 | 상품 ID |
| confidence | float32 | 감지 신뢰도 (0.0~1.0) |
| bbox | shopee_interfaces/BBox | Bounding Box |
| bbox_number | int32 | BBox 번호 (앱 UI 선택용) |
| detection_info | shopee_interfaces/DetectionInfo | 다각형 영역 정보 |
| pose | shopee_interfaces/Pose6D | 6D Pose |
| 필드명 | 타입 | 설명 |
|---|---|---|
| x1 | int32 | 좌상단 x |
| y1 | int32 | 좌상단 y |
| x2 | int32 | 우하단 x |
| y2 | int32 | 우하단 y |
| 기능 | 토픽명 | 메시지 타입 | 송신 | 수신 | 주요 필드 및 설명 |
|---|---|---|---|---|---|
| 자세 변경 상태 | /packee/arm/pose_status | shopee_interfaces/msg/ArmPoseStatus.msg | Pac Arm | Pac Main |
|
| 픽업 상태 | /packee/arm/pick_status | shopee_interfaces/msg/ArmTaskStatus.msg | Pac Arm | Pac Main |
|
| 담기 상태 | /packee/arm/place_status | shopee_interfaces/msg/ArmTaskStatus.msg | Pac Arm | Pac Main |
|
| 기능 | 서비스명 | 서비스 타입 | 송신 | 수신 | 요청(Request) 필드 | 응답(Response) 필드 | 비고 |
|---|---|---|---|---|---|---|---|
| 자세 변경 명령 | /packee/arm/move_to_pose | shopee_interfaces/srv/ArmMoveToPose.srv | Pac Main | Pac Arm | int32 robot_id int32 order_id string pose_type ("cart_view", "standby") |
bool success string message |
|
| 상품 픽업 명령 | /packee/arm/pick_product | shopee_interfaces/srv/ArmPickProduct.srv | Pac Main | Pac Arm | int32 robot_id int32 order_id string arm_side ("left", "right") shopee_interfaces/msg/DetectedProduct[] products |
bool success string message |
|
| 상품 담기 명령 | /packee/arm/place_product | shopee_interfaces/srv/ArmPlaceProduct.srv | Pac Main | Pac Arm | int32 robot_id int32 order_id int32 product_id string arm_side ("left", "right") shopee_interfaces/msg/Pose6D pose |
bool success string message |
|
| MTC 시작 | /packee/mtc/startmtc | shopee_interfaces/srv/PackeeMainStartMTC | Pac Main | Pac Arm | int32 robot_id int32 order_id shopee_interfaces/Sequence[] sequences |
bool success string message |
|
| MTC 완료 | /packee/mtc/finish | shopee_interfaces/srv/PackeeArmPackingComplete | Pac Arm | Pac Main | int32 robot_id int32 order_id shopee_interfaces/Sequence[] sequences bool success string message |
bool success string message |
| 필드명 | 타입 | 설명 |
|---|---|---|
| product_id | int32 | 상품 ID |
| bbox_number | int32 | BBox 번호 |
| detection_info | DetectionInfo | 다각형 영역 정보 |
| bbox | BBox | Bounding Box |
| confidence | float32 | 감지 신뢰도 (0.0~1.0) |
| pose | Pose6D | 6D Pose |
| 필드명 | 타입 | 설명 |
|---|---|---|
| polygon | Point2D[] | 다각형 좌표 |
| bbox_coords | BBox | BBox 좌표 |
| 필드명 | 타입 | 설명 |
|---|---|---|
| x | float32 | x 좌표 |
| y | float32 | y 좌표 |
| 필드명 | 타입 | 설명 |
|---|---|---|
| x1 | int32 | 좌상단 x |
| y1 | int32 | 좌상단 y |
| x2 | int32 | 우하단 x |
| y2 | int32 | 우하단 y |
| 필드명 | 타입 | 설명 |
|---|---|---|
| x | float32 | 위치 x |
| y | float32 | 위치 y |
| z | float32 | 위치 z |
| rx | float32 | 회전 x |
| ry | float32 | 회전 y |
| rz | float32 | 회전 z |
| 필드명 | 타입 | 설명 |
|---|---|---|
| seq | int32 | 시퀀스 번호 |
| id | int32 | ID |
| x | float64 | 위치 x |
| y | float64 | 위치 y |
| z | float64 | 위치 z |
| rx | float64 | 회전 x |
| ry | float64 | 회전 y |
| rz | float64 | 회전 z |
| 기능 | 서비스명 | 서비스 타입 | 송신 | 수신 | 요청(Request) 필드 | 응답(Response) 필드 |
|---|---|---|---|---|---|---|
| MTC Vision 전달 | /packee/picking/ibvs | shopee_interfaces/srv/ArmPickProduct.srv | Pac Arm | Pac Vision | int32 robot_id int32 order_id int32 product_id string arm_side (Packee: 'left'/'right', Pickee: '') shopee_interfaces/Pose6D pose |
bool success string message |
| 필드명 | 타입 | 설명 |
|---|---|---|
| x | float32 | 위치 x |
| y | float32 | 위치 y |
| z | float32 | 위치 z |
| rx | float32 | 회전 x |
| ry | float32 | 회전 y |
| rz | float32 | 회전 z |
Shopee App (사용자 화면)
Shopee Main (서버 & 통신)
Shopee LLM (음성인식)
LLM 파트는 크게 다음 두 상황을 지원
- 영업 중 : 고객 대상 음성 검색(상품 정보 조회)
- 구조 :
고객 -> STT 모듈 -> LLM 모듈 -> Main Service -> APP
- 영업 종료 후 : 직원 대상 음성 주행(장소 이동) & 직원 Following
- 구조 :
직원 -> STT 모듈 -> LLM 모듈 -> Pickee
- 구조 :
STT 모듈은 주변 소음 환경에서도 안정적으로 발화 구간을 검출하기 위해 환경에 따른 음성 분석을 수행
- 입력 음성에 Fourier Transform 적용
- 주파수 영역에서 음성의 특성을 분석 -> 발화 시에만 power가 측정됨을 확인
- 발화 시작 임계값 적용
- 일정 시간(약 1초) 동안의 주변 소음 평균 Power를 계산
- 기준:
발화 시작 임계값 = 주변 소음 평균 Power × 10 - 입력 음성 Power가 위 임계값을 초과하면 발화 시작으로 인식
고객이 상품 정보를 음성으로 요청하면, STT와 LLM, DB, APP이 연동되어 정보를 제공하는 구조
- 고객 : 상품에 대해 질문을 진행
- 예)
"사과 알려줘","사과에 대해서 알려줄래?"
- 예)
- STT 모듈 : 사용자 음성을 텍스트로 변환 후 LLM에 입력
- Whisper 기반 STT 엔진 사용
- 음성 → 텍스트 변환 수행
- LLM 모듈 : 사용자 입력에서 상품명만 추출 후 쿼리문을 Main Service로 송신
- Tool Calling 기능을 이용, 상품 정보 관련 질문에만 쿼리문을 송신
- 입력된 상품 정보 관련 텍스트에서 상품명만 추출
- Main Service & APP
- Main Service: DB 모듈과 연동
- APP: 최종 상품 정보를 사용자에게 표출
영업 종료 후에는 직원의 보조를 위해,
장소 이동(음성 주행) 과 직원 Following 기능을 LLM 기반으로 제공
- 직원
- 예)
"과자로 가줘","과자코너로 이동해줘","따라와","나 좀 따라와줘"
- 예)
- STT 모듈
- Whisper 기반 STT 엔진 사용
- 음성 → 텍스트 변환 수행
- LLM 모듈 : Following 요청이 입력되면 서비스 콜을 수행하여 follow 모드로 변경, 장소 이동 요청 시 장소만 추출하여 ROS Topic으로 발행
- Tool Calling 기능을 이용, Following 관련 명령에만 서비스 콜을 수행
1. 직원이 Following 관련 음성을 발화 - 예: `"나 좀 따라와줘"`, `"따라와"` 2. STT 모듈이 텍스트로 변환 3. LLM 모듈은 텍스트를 분석해 **Following 명령 여부**를 판단 4. Following 요청일 경우, **사전에 설계된 Service Call** 실행 - 예: `robot_id : 1, mode : tracking` 5. Pickee 로봇이 직원 뒤를 따라가는 **Following 동작 수행**- 장소 이동 관련 명령에만 ROS Topic을 발행
1. 직원이 **장소 이동 관련 음성** 을 발화 - 예: `"과자 코너로 이동해줄래"`, `"과자로 가줘"` 2. STT 모듈이 텍스트로 변환 3. LLM 모듈은 텍스트에서 **장소명만 추출** - 예: `"과자"` 4. 추출된 장소명을 **장소 Topic** 으로 음성 주행 모듈에 발행 - 예: `"과자"` Topic Publish 5. 음성 주행 모듈은 해당 Topic을 수신해 지정된 장소로 자율 주행 수행 - 장소 이동 관련 명령에서는 이동 장소만 추출 후 토픽으로 발행 - 주행 모듈에서는 해당 토픽 구독 후 좌표로 변환하여 NAV2를 사용하여 주행
- 장소 이동 요청 시, Base LLM 모델 을 그대로 사용할 경우
- 장소명 추출 과정에서 할루시네이션(hallucination) 반복 발생
- 즉, 존재하지 않는 장소명을 만들어내거나, 의도와 다른 텍스트를 반환
- 이를 개선하기 위해 Fine-Tuning 진행이 필요 함을 확인
- 학습 데이터 셋
- 총 527개의 대화/명령 데이터 구축
- 특정 장소(예: 과자, 신선식품, 반납함 등)로 이동하는 요청에 초점을 맞춘 데이터
- 사용 프레임워크
unsloth+Transformers
- 학습 방식
- QLoRA 방식 으로 SFT(Supervised Fine-Tuning) 진행
- 베이스 모델 위에 저차원 어댑터(LoRA)를 얹어 효율적으로 학습 진행
- Base 모델 적용 LLM 모듈 실행 화면
- 할루시네이션 발생, 없음으로 판단
- Fine-Tuning 모델 적용 LLM 모듈 실행 화면
- 요청에 맞는 정확한 장소명 을 안정적으로 출력
- Fine-Tuning 이후, 음성 주행/Following 관련 LLM 응답의 신뢰성과 일관성이 크게 향상됨
Pickee Main (주행로봇 통신)
Pickee Mobile (매대 주행 및 정밀주차)
-
기능, 목적
-
Nav2를 활용한 자율 주행
지시한 목적지로 자율주행을 한다. 추가로 Ros2 토픽을 사용해서 속도를 제어한다. -
ArUco 마커를 활용한 정밀 주차
Nav2 만으로는 목적지에 정확하게 도착할 수 없었다. 매대의 상품을 Pickee arm 이 집기 위해서는 Pickee_Mobile이 매번 같은 위치에 일정하게 도착해야 하는데 이 요구사항을 수행하기 위해 ArUco 마커를 활용했다.
-
-
Nav2를 활용한 자율 주행
-
속도 조절 Nav2로 주행 중 로봇이 특정 토픽을 받으면 감속 혹은 일시정지를 해야 하는데 이렇게 유동적으로 속도를 제어했다. 기존에는 로봇이 /cmd_vel 토픽을 Subscribe해서 속도가 제어됐는데 해당 토픽을 Publish 하는 노드가 Nav2 패키지에 있어서 해당 코드를 수정할 수는 없었다. 그래서 로봇이 /cmd_vel_modified 토픽을 Subscribe 해서 속도가 제어되도록 설정을 바꿨고 새로은 노드를 만들었다. /cmd_vel 토픽을 Subscribe해서 속도를 변환한 다음 /cmd_vel_modified 토픽을 Publish 하는 vel_modifier 노드를 만들었다.
-
자율 주행 목적지를 전달 받으면 주행 서비스 요청, 이동중 위치 피드백, 도착 결과 Publish 이외에 매대까지 주행을 위한 기능들을 수행한다.
-
-
ArUco 마커를 활용한 정밀 주차
-
이미지 전처리
특정 상황에서 ArUco 마커가 카메라에 전부 나오는 경우에도 감지되지 않는 경우가 있었다. 12개의 매대 중 한 매대에서 특정 거리가 떨어져 있을 때만, 즉 매우 특수한 상황에서만 감지되지 않았다. RGB 이미지로 ArUco 마커감지를 실패하면 이미지 처리한 버전으로 다시 감지를 시도한다.cv2로 Grayscale 변환 후 이진화 처리를 했다.
-
좌표계 변환
ArUco 마커를 감지하는 기본 패키지를 사용 하면 카메라 기준 ArUco 마커의 좌표와 회전값이 나온다. 이 값을 활용해서 ArUco 마커기준 카메라의 좌표, 화전값을 구해서 정밀 주차 하는데 사용했다. 카메라가 Pickee Mobile 맨 앞에 있기 때문에 카메라의 좌표를 로봇의 좌표로 간주했다. -
x축 정렬(변환 후 좌표계 기준) 로봇이 ArUco 마커에 접근 하는 과정을 시뮬레이션 했을 때 x 오차를 줄이며 접근하는 과정에서 ArUco 마커가 카메라의 시야에서 벗어나는 경우가 많았다. 특히 로봇의 x 오차가 클수록 자주 벗어났다. 그래서 매대에 도착하면 ArUco 마커를 보고 x 오차가 줄어드는 방향으로 이동한 다음 ArUco 마커에 접근한다.
-
마커 접근, 오차 기반 속도 보정 x 좌표 오차에 비례해 x축 방향 속도가 결정되고 z 좌표 오차에 비례해 z축 방향 속도가 결정된다. 이때 z축 속도는 로봇의 전진속도지만 이 로봇은 차동구동 로봇이기 때문에 x축 방향 속도를 바로 결정할 수는 없다. 그래서 x축 속도 대신 yaw(카메라 기준 ArUco 마커가 틀어진 각도)를 x축 속도처럼 사용했다.
-
특정 거리, 각도 이동 로봇의 /odom 토픽을 구독해서 특정 거리를 전진하거나 특정 각도를 회전하게 했다.
-
Pickee Vision (상품 선택 시야)
-
데이터 수집 및 학습
- 상품을 집기 위한 준비 자세에서 변동성이 적은
$Z$ , Roll, Pitch 좌표는 고정하고, 변동성이 많은$X$ ,$Y$ , Yaw 좌표를 바꿔가며 이미지에 라벨링 하여 데이터를 수집 후 해당 CNN 모델을 이용해 학습을 진행했습니다.
- 상품을 집기 위한 준비 자세에서 변동성이 적은
-
Two Stream Network를 활용한 Pose 추정
- Two Stream Network에 두 가지 이미지를 입력합니다.
- 첫 번째는 고정된 Target Image이고, 두 번째는 로봇팔 캠에서 실시간으로 받아온 이미지입니다.
- 이 둘을 입력해 각각 Target Pose와 Current Pose를 구합니다.
Pickee Arm (로봇팔 제어 및 보정)
- 오차 발생 및 보정 필요성
- 데이터 수집 시 로봇팔의 위치는 고정되어 있었습니다. 그래서 현재 이미지를 CNN 모델에 넣어 예측할 때에도 고정적인 좌표가 도출됩니다.
- 그러나 로봇팔이 카트 위에 존재하기 때문에 실제 상품을 집을 때의 로봇팔의 위치는 고정되어 있지 않습니다.
- 따라서 로봇팔이 매대에 도착했을 때 생선의 위치가 학습했던 위치와 다르고, CNN으로 예측한 좌표와 실제 로봇팔의 좌표에 차이가 존재합니다.
-
이로 인해 CNN으로 추정한 Target Pose를 보정해줘야 할 필요가 있습니다.
-
목표 좌표 보정 및 제어
- 먼저 현재 좌표에 대한 차이를 구한 후, 목표 좌표를 보정했습니다.
- 보정된 목표 좌표와 로봇팔의 실시간 좌표의 차이를 이용해 PD 제어를 했습니다.
PhysicalAI
- YOLO11 기반 상품 감지 (Detection)
- 자체 촬영/라벨링 1,156장
- 이클립스/와사비/생선 등 18종 분류
- yolov8, yolov11 성능 비교 후 최종 yolo11로 선정
- PoseCNN 기반 6D Pose 추정 (Position + Orientation)
- ResNet18 Feature Extractor
- 512 → 256 → 6D Pose (x·y·z·rx·ry·rz)
- Two-Stream Network 기반 Visual Servoing
- 현재 이미지와 목표 이미지가 동일할때 까지 반복 제어
Packee Vision (포장대 이미지 학습 및 처리)
Packee Arm (포장대 로봇팔)
| 팀 | 이름 | 소감 |
|---|---|---|
| App | 김윤재 | 로봇 분야를 접해볼 수 있어서 재밌었고, 주변 사람들이 잘 챙겨주셔서 감사합니다. 좋은 분들과 만날수 있어서 좋았습니다. |
| Main | 장진혁 | 친절하고 매너있는 팀원 만나서 프로젝트 하는 하루하루가 기분 좋게 흘러갔습니다. |
| LLM | 김재형 | 부트캠프 목표가 있었는데 다 이루어서 좋았습니다. 팀이 성향이랑 잘 맞아서 너무 재밌었고 같이 해서 영광이었습니다! |
| Pickee 주행 | 최원호 | 주행 파트를 혼자가 아닌 함께 구현해서, 같은 업무 안에서 협업하는 경험을 쌓아 좋았습니다. |
| Pickee 주행 | 임어진 | 실제 로봇 가지고 주행해본 것, 협업해본 경험이 생겨서 너무 좋았습니다. 모르는 거 생겼을 때 다들 도와주셔서 감사했습니다. |
| Pickee 상품선택 | 이승한 | 개발 방법론을 잘 배워가서 뜻깊었습니다. 팀원들끼리 서로 도우면서 잘 마무리한거 같아서 좋았습니다. |
| Pickee 상품선택 | 류혜진 | 로봇을 배우기 좋았습니다. 다들 친절히 알려주어 많이 배웠습니다. 감사합니다! |
| Packee | 송원준 | 로봇팔 하려고 부트캠프에 왔는데, 잘 되어서 좋았습니다. 처음엔 주제 정하면서 어렵기도 했지만 잘 마무리 된 거 같아서 뿌듯합니다. |
| Packee | 이한수 | 로봇팔도 하고, 비전 AI도 해보고 좋은 경험이 되었습니다. 서기랑 디자인 맡아주신 분께도 너무 감사합니다. |
| Packee | 박대준 | 2개월동안 팀원들과 함께해서 보람찼고, 많이 배웠습니다! |




























































