MacGyvBot: 음성/GUI 기반 공구 전달 및 반납 로봇 어시스턴트
MacGyvBot은 작업자가 공구 보관 장소까지 직접 이동하지 않아도, 로봇팔이 필요한 공구를 찾아 전달하고 사용 후 다시 서랍에 정리하는 ROS 2 기반 로봇 어시스턴트 프로젝트이다. 사용자는 음성 또는 GUI로 "드라이버 가져다줘", "이 공구 정리해줘", "멈춰", "재개" 같은 명령을 입력하고, 시스템은 이를 구조화된 robot task로 변환한다.
전체 시스템은 Command, Task Coordinator, Perception, Manipulation, Operator UI, Safety 계층으로 구성했다. ROS 2의 node, topic, service, action 개념을 기준으로 기능 책임을 분리하고, 센서 데이터와 detection 결과처럼 지속적으로 흐르는 정보는 topic으로, 명확한 요청/응답이 필요한 판단은 service로, 시간이 걸리고 중간 취소가 필요한 manipulation 흐름은 action과 task queue로 관리하는 방향을 잡았다.
Perception은 RealSense RGB-D, YOLO, SAM+Depth, PCA, hand landmark ML classifier를 활용해 공구 위치, 파지점, 방향각, 사용자 handoff 상태를 판단한다. Manipulation은 Doosan M0609, MoveIt, OnRobot RG2 gripper를 사용해 서랍 접근, 공구 파지, 사용자 전달, 반납, 서랍 닫기 동작을 수행한다.
프로젝트에서 나는 PM 및 통합 담당 역할을 수행했다. 일정 관리, 업무 분담, QA, 시연 시나리오 구성, 발표 흐름 정리, 팀원 간 커뮤니케이션 조율을 맡았다.
기술적으로는 ROS 2 패키지 책임 분리, perception 방식 비교, YOLO 학습/평가 방향 제시, VLM/VLM-only/API 기반 grasp point 실험, SAM+Depth mask와 PCA 기반 yaw 계산 검증, GUI 개선 아이디어, structured log 통일, 코드 리팩토링, TaskStep Queue 기반 멈춤/재개/recovery 구조 설계에 참여했다.
또한 실제 로봇 시연 과정에서 발생한 planning 실패, depth projection 실패, handoff 실패, 서랍 충돌, return drawer validation 실패, wrist joint branch 문제를 QA 로그로 정리하고, 원인을 perception, TF/depth, MoveIt planning scene, controller, gripper, task orchestration 계층으로 나누어 개선 방향을 조율했다.
초기에는 기능들이 하나의 흐름 안에 섞여 있어 문제가 발생했을 때 원인을 추적하기 어려웠다. 이를 Command, Task, Perception, Manipulation, UI, Config, Interfaces 등 역할별 패키지 구조로 바라보고, 각 계층이 ROS topic/service/message 계약을 통해 연결되도록 정리했다.
이 과정에서 ROS 2를 단순 실행 도구가 아니라 분산 로봇 시스템의 구조로 이해했다. 카메라 이미지, detection result, task status, joint state처럼 계속 갱신되는 데이터는 topic으로 흐르게 하고, perception 요청이나 상태 확인처럼 요청/응답이 명확한 동작은 service 성격으로, 로봇 팔 이동이나 pick-and-place처럼 시간이 걸리고 취소가 필요한 작업은 action/task step으로 관리하는 기준을 세웠다.
이 구조 덕분에 자연어 명령 오류, perception 실패, MoveIt planning 실패, UI 표시 문제를 각각 분리해서 디버깅할 수 있었다.
bring/return은 단일 동작이 아니라 서랍 접근, 공구 탐지, depth 보정, 파지, 전달, 반납, 복구가 연결된 긴 흐름이다. ROS 2 Action만으로는 전체 작업의 중간 상태, 남은 단계, 복구 후 재개를 관리하기 어렵다고 판단했다.
그래서 작업을 TaskStep 단위로 나누고 queue로 관리하는 구조를 적용했다. pause 시 현재 MoveIt goal을 cancel하고 suspended step과 남은 queue를 보존하며, resume 시 중단된 step부터 다시 실행하도록 설계했다. cancel과 exit도 구분해 cancel은 queue 정리, exit는 home 복귀와 gripper open까지 포함하도록 분리했다.
이를 통해 pause, resume, cancel, drop recovery 후 원래 작업 복귀를 더 유연하게 처리할 수 있었다.
concept notes에서 정리한 CV 흐름은 픽셀 전처리, feature extraction, CNN, object detection, segmentation, multimodal model로 확장된다. MacGyvBot에서는 이 흐름을 단순 학습 내용으로 두지 않고, 실제 perception pipeline 판단 기준으로 연결했다.
이미지 전처리 관점에서는 조명, 대비, 노이즈, ROI가 thresholding, segmentation, detection 결과를 흔들 수 있음을 고려했다. Detection 관점에서는 YOLO가 class와 bbox를 잘 내더라도 bbox가 실제 grasp pipeline에 사용할 수 있는 품질인지 따로 보았다. Segmentation 관점에서는 bounding box보다 실제 공구 영역 mask가 파지점과 yaw 추정에 더 직접적인 정보를 준다고 판단했다.
최종적으로는 task-specific YOLO로 공구 후보와 grasp point의 x, y를 안정화하고, SAM+Depth mask에서 실제 공구 영역을 확보한 뒤, PCA로 긴 축을 계산해 yaw를 얻는 방식이 실제 로봇 제어에 더 적합하다고 판단했다.
YOLO나 SAM의 결과는 이미지 좌표계에 있는 2D 정보이므로 로봇이 바로 사용할 수 없다. Depth 값, camera intrinsic, hand-eye calibration, TF 변환을 거쳐 camera frame의 3D point를 robot base frame의 목표 pose로 바꿔야 한다.
이 관점에서 depth=0, camera info 불일치, frame transform 오류가 겉으로는 perception 실패나 planning 실패처럼 보일 수 있음을 QA 기준에 포함했다. 실제 pick target 계산에서는 bbox center나 mask point를 depth와 결합하고, TF를 통해 MoveIt이 해석할 수 있는 frame으로 변환하는 흐름을 점검했다.
이 경험을 통해 "CV가 물체를 찾았다"와 "로봇이 그 물체를 잡을 수 있다" 사이에는 depth projection, calibration, TF, safe workspace clamp가 반드시 필요하다는 점을 프로젝트 설명의 핵심 메시지로 정리했다.
MoveIt은 목표 좌표로 로봇을 보내는 단순 함수가 아니라, 로봇 모델, planning scene, collision checking, trajectory generation, controller execution을 연결하는 motion planning 프레임워크다. 이를 바탕으로 planning 실패를 볼 때도 단순히 목표 pose만 보지 않고 URDF/Xacro의 link/joint 구조, collision geometry, joint limit, planning group, controller 연결, TF, planning scene object를 함께 확인했다.
서랍 collision scene 문제에서는 collision object가 안전성을 높이지만, 크기나 적용 시점이 보수적이면 gripper 접근 경로까지 막아 planning이 실패할 수 있음을 확인했다. 따라서 collision object는 "많이 넣을수록 안전하다"가 아니라 실제 작업 가능성과 균형을 맞춰야 한다고 정리했다.
또한 wrist joint branch 문제에서는 같은 end-effector pose에도 여러 IK 해가 존재할 수 있음을 바탕으로, 현재 joint state와 가장 가까운 후보를 선택하고 joint_6 equivalent angle을 비교하는 방향을 제안했다.
초기 handoff 판단은 손과 공구의 거리, overlap, depth 조건을 조합한 rule-based 방식이었다. 그러나 손이 실제로 공구를 잡지 않았는데도 release 조건이 만족될 수 있어 안전 문제가 있었다.
이를 해결하기 위해 판단 기준을 "손이 공구 근처에 있는가"에서 "손이 grasp gesture를 하고 있고 실제 공구 표면과 접촉했는가"로 바꾸었다. hand landmark ML classifier로 open/grasp를 분류하고, SAM+Depth mask로 공구 표면을 유지하며, 손 landmark와 mask/depth 접촉 및 시간 안정성을 함께 확인하는 구조로 개선했다.
이 방향은 handoff를 단순 인식 결과가 아니라 release 전 safety gate로 다루는 데 의미가 있었다.
Isaac Sim은 센서, 물체, 로봇 제어, 물리 환경을 한 장면 안에서 검증할 수 있는 시뮬레이션 환경이다. 프로젝트에서는 실제 로봇 실험의 한계를 보완하기 위해 Isaac Sim을 활용해 pick-and-place 구조, gripper assembly, sensor simulation, controller 흐름을 검증하는 방향을 검토했다.
특히 서랍 개폐나 handoff 같은 접촉 기반 동작은 단순 transform 애니메이션보다 joint constraint, collider, rigid body, contact sensor 같은 물리 설정이 중요하다고 보았다. 이 관점은 실제 로봇에서 collision scene과 gripper 접촉 문제가 발생했을 때 원인을 더 구조적으로 나누는 데 도움이 되었다.
실제 로봇 테스트에서는 "멈춰 후 재개 불가", "drawer_prepare_failed", "depth=0으로 pick target 보정 실패", "return drawer에 다른 공구 감지", "joint_6 목표각 branch 문제", "서랍 collision scene이 planning을 막는 문제" 등이 발생했다.
각 로그를 [pkg], [pipe], [msg], [reason], [tool], [stage] 형식으로 정리하여 어느 계층에서 실패했는지 빠르게 파악할 수 있도록 했다. 이는 팀원들이 각자 다른 방식으로 로그를 남기던 문제를 줄이고, QA와 트러블슈팅 속도를 높이는 데 도움이 되었다.
문제 상황
초기에는 VLM이 이미지를 보고 적절한 grasp point와 yaw를 추론하도록 구성하려 했다. SmolVLM, Qwen 3B/7B, Gemini API, grid prompt 방식 등을 실험했지만, 프롬프트에 따라 결과가 흔들리고 추론 시간이 길어 실제 로봇 제어 입력으로 사용하기 어려웠다.
원인
VLM foundation model은 일반적인 이미지 이해에는 강점이 있지만, 특정 공구의 실제 파지 가능 지점과 로봇 gripper 방향각을 안정적으로 출력하기에는 도메인 데이터와 fine-tuning이 부족했다. 또한 실제 로봇 제어에는 픽셀 좌표의 작은 오차도 큰 실패로 이어질 수 있었다.
해결
VLM 단독 방식을 최종 제어 입력으로 사용하지 않고, task-specific YOLO와 SAM+Depth+PCA 기반 방식으로 전환했다. YOLO는 공구 및 grasp point의 x, y 좌표를 안정화하고, SAM mask와 depth는 실제 공구 영역을 보강하며, PCA는 mask에서 공구의 긴 축을 계산해 yaw를 제공하도록 했다.
결과
범용 AI 모델보다 도메인 특화 모델과 기하학적 알고리즘을 조합하는 방식이 실제 로봇 환경에서 더 빠르고 안정적이라는 결론을 얻었다.
초기에는 최근 로봇 연구에서 자주 사용되는 VLM + VLA 구조도 고려했다. VLM이 사용자의 명령을 바탕으로 전체 작업 계획을 세우고, VLA가 현재 카메라 프레임을 보며 다음 행동 또는 짧은 행동 시퀀스를 예측해 로봇을 움직이는 구조를 생각했다.
하지만 실제 프로젝트에서는 VLA를 바로 적용하기 어려운 제약이 있었다. VLA는 현재 상태에서 다음 행동을 예측하는 방식이기 때문에 long-horizon task 전체를 안정적으로 수행하려면 실시간성, 제어 주기, 실패 복구, 환경 변화 추적 문제가 함께 해결되어야 했다. 또한 이 프로젝트에서는 MoveIt을 통해 좌표 기반 motion planning을 이미 처리하고 있었기 때문에, VLA가 직접 action을 예측하는 구조는 오히려 시스템을 복잡하게 만들 수 있었다.
그래서 처음에는 VLM을 활용해 공구 이미지에서 grasp point와 yaw를 직접 얻으려 했다. VLM only 방식, YOLO bbox crop 후 grid를 나누어 VLM이 잡기 좋은 cell을 고르는 방식, Gemini API를 활용하는 방식까지 비교했다. Grid 방식은 VLM이 완전히 엉뚱한 곳을 고르는 문제를 줄일 수 있었지만, latency가 증가했고 결과의 일관성을 완전히 보장하지 못했다. Qwen 3B/7B처럼 더 큰 모델도 사용해 봤지만 추론 시간은 늘어난 반면 실제 로봇 제어에 믿고 넣을 만큼 안정적인 x, y, yaw를 제공하지는 못했다.
결국 이 문제는 "일반적인 VLM이 모든 상황에서 grasp point를 알아서 찾아줄 것"이라는 기대가 너무 낙관적이었다는 결론으로 이어졌다. 실제 로봇 manipulation에서는 한두 픽셀의 오차, yaw 계산 실패, 마스크 흔들림이 바로 grasp 실패나 충돌 위험으로 이어질 수 있었다.
최종적으로는 task-specific YOLO로 공구와 grasp point를 직접 탐지하고, SAM과 depth mask를 결합해 공구 영역을 안정화한 뒤, PCA로 공구의 긴 축을 계산해 yaw를 얻는 구조를 선택했다. 공구 대부분이 길쭉한 형태라는 도메인 특성을 활용했기 때문에 PCA 기반 yaw 계산이 잘 맞았고, VLM보다 범용성은 낮지만 실제 시연 환경에서는 더 예측 가능하고 디버깅하기 쉬운 방식이었다.
최종 perception 흐름은 다음과 같이 정리할 수 있다.
사용자 명령
-> 대상 공구 결정
-> YOLO로 공구 / grasp point 탐지
-> SAM + Depth mask로 공구 영역 보정
-> PCA로 yaw 계산
-> MoveIt으로 접근 및 grasp 수행
-> 실패 시 recovery sequence 실행
이 과정에서 얻은 가장 큰 교훈은 로봇 제어에서는 "똑똑한 모델 하나"보다 "불확실성을 줄이는 작은 모듈들의 조합"이 더 실용적일 때가 많다는 점이다. VLM/VLA는 향후 planner나 action adapter 형태로 확장할 수 있지만, 실제 제어 입력은 반복 가능하고 실패 원인을 추적할 수 있는 구조가 먼저 필요했다.
문제 상황
YOLO가 공구를 검출해도 bbox가 공구 본체를 충분히 포함하지 않거나, 서랍 내부/그리퍼 접근 순간/부분 가림 상황에서 bbox가 흔들리면 후속 SAM, depth mask, PCA yaw 계산이 실패했다.
원인
객체 탐지의 성공 기준과 로봇 파지 성공 기준이 달랐다. 단순히 class가 맞는 것만으로는 충분하지 않았고, bbox가 후속 grasp pipeline에 사용할 수 있는 품질이어야 했다. confidence가 높아도 box 위치가 부정확하거나 NMS/threshold 설정 때문에 목표가 사라지면 로봇 작업은 실패할 수 있었다.
해결
YOLO 평가 기준을 단순 mAP가 아니라 "grasp pipeline에 사용할 수 있는 bbox인지"로 재정의했다. 클래스가 맞는지, 공구 본체를 충분히 포함하는지, SAM/depth/PCA로 이어질 수 있는지를 success condition으로 잡았다. 또한 runtime confidence threshold, NMS 영향, condition별 success rate, bbox usable for grasp rate를 평가하도록 정리했다.
결과
Perception 결과를 로봇 작업 관점에서 평가하는 기준을 세웠고, 발표와 QA에서도 "AI가 잘 된다"가 아니라 "후속 grasp에 쓸 수 있는가"를 중심으로 설명할 수 있게 되었다.
문제 상황
Detection이나 segmentation 결과가 있어도 depth 값이 0이거나 camera frame에서 robot base frame으로 변환이 맞지 않으면 pick target이 엉뚱한 위치로 계산되었다.
원인
2D 이미지 좌표는 로봇의 목표 pose가 아니다. 픽셀 좌표를 3D camera coordinate로 바꾸려면 depth와 camera intrinsic이 필요하고, 로봇이 움직이려면 hand-eye calibration과 TF를 통해 base frame으로 변환해야 한다. 이 중 하나라도 틀리면 perception 오류처럼 보이지만 실제 원인은 좌표계 연결일 수 있다.
해결
depth topic과 camera info topic을 함께 확인하고, depth=0인 경우를 명시적으로 실패 처리하도록 QA 기준에 포함했다. 또한 RViz에서 TF frame과 marker 위치를 확인해 detection result, camera frame, robot base frame, MoveIt target pose가 같은 좌표 흐름 안에 있는지 점검했다.
결과
perception과 manipulation 사이의 실패 지점을 더 정확히 나눌 수 있었고, "검출 성공" 이후에도 depth/calibration/TF 검증이 필요하다는 점을 팀 내 공통 기준으로 만들 수 있었다.
문제 상황
서랍 접근, drawer observe, pick/refine step 중 "멈춰"를 입력하면 현재 MoveIt goal은 취소되지만, 이후 "재개" 시 어느 단계부터 다시 실행해야 하는지 불명확한 문제가 있었다. 일부 상황에서는 drawer_prepare_failed로 재개가 실패하거나, task step 시작 전 pause 시 resume이 불가능했다.
원인
bring/return은 단일 action goal이 아니라 여러 단계가 연결된 복합 작업이다. 현재 step, 남은 queue, target tool, perception 결과, recovery 상태를 함께 보존하지 않으면 중단 이후 재개할 수 없다.
해결
TaskStep Queue 개념을 도입해 전체 작업을 작은 단계로 분해했다. pause 시 현재 MoveIt goal을 cancel하고 suspended step과 남은 queue를 보존하며, resume 시 중단된 step부터 다시 실행하도록 설계했다.
결과
작업 흐름이 긴 스크립트가 아니라 중지, 재개, 취소, 복구가 가능한 상태 기반 구조로 개선되었다.
문제 상황
초기 rule-based handoff 판단은 손과 공구가 가까워지거나 ROI가 겹치면 사용자가 공구를 잡았다고 판단할 수 있었다. 하지만 실제로는 손이 공구를 잡지 않았는데도 release가 발생할 수 있어 위험했다. 반대로 손이나 그리퍼가 공구를 가리면 YOLO bbox가 사라져 판단 자체가 어려웠다.
원인
bbox와 거리 기반 규칙만으로는 실제 "사람이 공구를 잡았다"는 상태를 안정적으로 판단하기 어려웠다. 특히 사용자 손과 로봇 gripper가 가까운 상황에서는 false positive가 안전 문제로 이어질 수 있었다.
해결
판단 기준을 "손이 공구 근처에 있는가"에서 "손이 grasp gesture를 하고 있고 실제 공구 표면과 접촉했는가"로 바꾸었다. hand landmark ML classifier로 open/grasp를 분류하고, SAM+Depth mask로 공구 표면을 유지하며, 손 landmark와 mask/depth 접촉 및 시간 안정성을 함께 확인하도록 구성했다.
결과
로봇이 공구를 너무 일찍 놓는 위험을 줄이고, handoff 판단을 safety gate 기반으로 강화할 수 있었다.
문제 상황
서랍을 collision object로 planning scene에 넣으면 로봇이 위험한 경로를 피할 수 있지만, 일부 경우에는 gripper와 drawer collision object가 너무 보수적으로 충돌 판정되어 planning이 실패했다.
원인
실제 로봇에서는 서랍 손잡이를 잡고 접근해야 하는데, collision scene이 이를 단순 장애물로만 인식하면 필요한 접근 경로까지 막을 수 있다. 안전을 위한 모델링이 오히려 작업 실행을 방해하는 상충 관계가 생겼다.
해결
RViz와 MoveIt planning scene을 함께 확인하면서 collision object 적용 범위와 시점을 조정했다. URDF/Xacro의 visual, collision, inertial 차이를 구분하고, collision geometry가 실제 작업 가능성을 과하게 막지 않는지 확인하는 기준을 세웠다.
결과
안전 기능은 단순히 많이 넣는 것이 아니라, 실제 작업 가능성과 균형을 맞춰야 한다는 것을 배웠다.
문제 상황
MoveIt이 pose goal을 만족하는 IK 해를 선택할 때 현재 자세와 멀리 떨어진 branch를 선택하면 손목 관절이 불필요하게 크게 회전하거나 joint limit에 가까워지는 문제가 발생했다.
원인
같은 end-effector pose라도 여러 IK 해가 존재할 수 있고, MoveIt 내부 선택에만 맡기면 현재 관절 상태에서 가장 자연스러운 해가 선택된다는 보장이 없었다.
해결
현재 joint state를 기준으로 여러 IK 후보를 비교하고, joint delta가 가장 작은 후보를 선택하는 방향으로 개선했다. 특히 joint_6에 대해서 equivalent angle 후보를 만들고, joint limit과 현재 각도 차이를 기준으로 필터링했다.
결과
의도하지 않은 손목 회전 위험을 줄이고, 실제 로봇 동작의 예측 가능성을 높였다.
문제 상황
처음에는 기본 bring/return 성공 시연에 집중했지만, 실제 로봇에서는 공구 없음, 다른 공구 감지, handoff 실패, drop, planning 실패, 멈춤/재개 실패 등 다양한 상황이 발생했다.
원인
실제 작업 환경은 항상 정상 상태가 아니며, 로봇 시스템은 실패 상황을 설명하고 안전하게 멈추거나 복구해야 한다.
해결
시연 시나리오를 기본 bring/return뿐 아니라 drop 성공/실패, 멈춤-재개, inspection 실패, handoff 실패, drawer에 다른 공구가 있는 경우, 서랍에 공구가 없는 경우, return grasp 실패 등으로 확장했다. Isaac Sim과 RViz 관점에서는 시뮬레이션/시각화가 단순 화면 확인이 아니라 sensor, TF, planning scene, controller 상태를 검증하는 도구라는 점도 함께 설명했다.
결과
포트폴리오 관점에서 단순 데모 구현이 아니라 QA, 실패 정의, recovery 설계까지 고려한 프로젝트로 정리할 수 있게 되었다.
ROS 2, MoveIt, YOLO/SAM/Depth/PCA 기반 perception, TaskStep Queue 기반 작업 조율을 통합해 음성/GUI 명령으로 공구 가져오기와 반납을 수행하는 로봇 어시스턴트를 개발하고, QA·트러블슈팅·시연 설계·팀 일정 관리를 담당했다.
이 프로젝트에서 가장 크게 배운 점은 "AI 모델이 잘 맞히는 것"과 "로봇이 실제로 안전하게 작업을 완수하는 것"은 다르다는 점입니다. YOLO나 VLM이 이미지에서 결과를 내더라도, 그 결과는 아직 2D 인식 정보일 뿐입니다. 실제 로봇 작업이 되려면 depth, camera intrinsic, hand-eye calibration, TF 변환, yaw 계산, gripper width, safe workspace clamp, MoveIt planning, collision scene, controller 실행, 사용자 handoff 안전성까지 모두 맞아야 합니다.
그래서 저는 단순 모델 적용보다 전체 시스템에서 실패가 발생하는 지점을 나누는 데 집중했습니다. ROS 2 통신 구조로 책임을 분리하고, TaskStep Queue로 긴 작업을 상태 기반으로 관리하며, structured log와 QA 시나리오를 통해 perception, planning, manipulation, UI 문제를 구분해 개선했습니다. 이 경험을 통해 지능형 로봇 프로젝트에서는 모델 성능뿐 아니라 시스템 통합, 안전 조건, 실패 복구 설계가 실제 완성도를 결정한다는 점을 배웠습니다.