<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Jack_AI</title>
        <link>https://velog.io/</link>
        <description>AI 공부합니다</description>
        <lastBuildDate>Mon, 22 Jun 2026 05:20:34 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Jack_AI</title>
            <url>https://velog.velcdn.com/images/jack_7711/profile/5d9e22e1-c6d1-4aa0-ad96-6e75f87ef7ba/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Jack_AI. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jack_7711" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Robotics] 6. Robot CV Connection 정리 ]]></title>
            <link>https://velog.io/@jack_7711/Robotics-Robot-CV-Connection-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Robotics-Robot-CV-Connection-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 22 Jun 2026 05:20:34 GMT</pubDate>
            <description><![CDATA[<h1 id="0-전체-내용-요약과-키워드">0. 전체 내용 요약과 키워드</h1>
<p>이 문서는 ROS2, 로봇 모델링, MoveIt, 컴퓨터비전이 하나의 로봇 작업 파이프라인으로 연결되는 과정을 정리한다. CV는 이미지에서 물체, 영역, 특징을 찾지만, 로봇이 행동하려면 그 결과가 depth, camera intrinsic, hand-eye calibration, TF를 거쳐 robot base 좌표계의 3D 위치로 바뀌어야 한다.</p>
<p>실습 코드는 camera color/depth/camera_info topic을 subscribe하고, pixel에서 depth를 읽고, camera 좌표를 base 좌표로 변환한 뒤 MoveIt pick-and-place로 넘기는 흐름을 보여 준다. Click-to-pick과 bar sorting은 <code>image topic -&gt; detection/click -&gt; depth lookup -&gt; 3D projection -&gt; base transform -&gt; planning -&gt; gripper</code>로 이어지는 대표 pipeline이다. 이 문서는 앞의 개념들을 실제 로봇 행동으로 묶는 통합 단계로 보면 된다.</p>
<p><strong>키워드</strong>: Robot-CV pipeline, perception, RGB image, depth image, CameraInfo, intrinsic, pixel coordinate, depth lookup, point cloud, hand-eye calibration, TF, camera frame, base frame, detection, segmentation, click-to-pick, bar sorting, MoveIt, planning, gripper, pick-and-place, ROS2 topic</p>
<h1 id="1-컴퓨터비전-학습-흐름">1. 컴퓨터비전 학습 흐름</h1>
<h2 id="11-cv-학습-흐름">1.1. CV 학습 흐름</h2>
<h3 id="111-왜-전체-흐름을-먼저-잡아야-하는가">1.1.1. 왜 전체 흐름을 먼저 잡아야 하는가</h3>
<p>컴퓨터비전 수업은 개별 알고리즘을 따로 외우는 방식으로 이해하면 흐름이 끊긴다. 이미지 표현과 전처리에서 시작해 segmentation, morphology, feature matching, CNN, augmentation, object detection, semantic segmentation, foundation model로 이어지는 순서를 잡아야 각 개념이 왜 등장했는지 보인다.</p>
<p>초반 영상처리 개념은 픽셀과 필터, threshold, morphology처럼 사람이 설계한 규칙 기반 방법을 다룬다. 중반에는 feature extraction과 matching을 통해 이미지 사이의 대응 관계와 기하 변환을 이해한다. 후반에는 CNN과 딥러닝 모델을 통해 데이터로부터 feature를 학습하는 방식으로 넘어간다. 마지막으로 YOLO, U-Net, ViT, CLIP은 detection, segmentation, Transformer, multimodal foundation model로 확장된다.</p>
<h3 id="112-고전-영상처리에서-딥러닝까지">1.1.2. 고전 영상처리에서 딥러닝까지</h3>
<p>고전 영상처리는 이미지의 픽셀 값과 지역 패턴을 사람이 설계한 연산으로 처리한다. Histogram equalization, thresholding, erosion, dilation, SIFT, ORB 같은 방법이 여기에 속한다. 이 방법들은 데이터가 적거나 문제 구조가 명확할 때 해석 가능성이 높다.</p>
<p>딥러닝 기반 CV는 feature를 사람이 직접 설계하지 않고 데이터로부터 학습한다. CNN은 convolution filter를 학습하고, YOLO는 detection을 end-to-end로 수행하며, U-Net은 픽셀 단위 segmentation을 학습한다. ViT와 CLIP은 이미지를 patch sequence나 이미지-텍스트 임베딩으로 확장한다.</p>
<h3 id="113-로봇-수업과-연결되는-지점">1.1.3. 로봇 수업과 연결되는 지점</h3>
<p>CV는 로봇에게 주변 세계를 읽어 주는 perception 역할을 한다. Segmentation은 작업 영역과 물체 영역을 나누고, YOLO는 작업 대상 후보를 찾고, feature matching은 시점 변화나 기하 관계를 추정하며, CLIP은 언어 지시와 시각 정보를 연결하는 방향으로 확장된다.</p>
<p>이 결과들은 ROS2 topic으로 전달되고, TF와 depth 정보를 통해 로봇 좌표계로 변환되며, MoveIt planning scene이나 목표 pose로 연결된다. 따라서 CV 전체 흐름은 로봇 제어와 분리된 이미지 처리 과목이 아니라 지능형 로봇의 perception 기반으로 이해해야 한다.</p>
<h3 id="114-한-줄-정리">1.1.4. 한 줄 정리</h3>
<p>컴퓨터비전 학습 흐름은 픽셀 기반 전처리에서 시작해 feature, CNN, detection, segmentation, multimodal 인식으로 확장되며, 로봇 perception의 기반이 된다.</p>
<h2 id="12-robot-cv-pipeline">1.2. Robot-CV Pipeline</h2>
<h3 id="121-로봇-perception과-cv의-연결">1.2.1. 로봇 Perception과 CV의 연결</h3>
<ul>
<li><strong>왜 연결해서 이해해야 하는가</strong></li>
</ul>
<p>로봇 수업과 CV 수업은 따로 떨어진 과목처럼 보일 수 있지만, 실제 지능형 로봇 시스템에서는 강하게 연결된다. CV는 로봇이 주변 세계를 인식하게 해 주고, ROS2는 그 인식 결과를 시스템 안에서 전달하며, MoveIt과 controller는 인식 결과를 실제 로봇 행동으로 바꾼다.</p>
<p>따라서 CV를 단순 이미지 처리로만 이해하거나, ROS2/MoveIt을 단순 로봇 제어로만 이해하면 전체 흐름이 보이지 않는다. 로봇은 “보고, 해석하고, 계획하고, 움직이는” 시스템이다.</p>
<ul>
<li><strong>Perception 입력</strong></li>
</ul>
<p>로봇 perception의 입력은 카메라 이미지, depth image, point cloud, LiDAR, IMU, contact sensor 등이다. CV 수업에서 다룬 이미지 전처리, segmentation, morphology, feature matching, YOLO, U-Net, ViT, CLIP은 이 입력에서 의미 있는 정보를 추출하기 위한 방법들이다.</p>
<p>카메라 이미지는 2D 픽셀 좌표계에 있다. 로봇이 행동하려면 이 정보를 3D 공간과 로봇 좌표계로 연결해야 한다. 따라서 camera calibration, depth, TF 변환이 필요하다.</p>
<ul>
<li><strong>Detection에서 로봇 행동까지</strong></li>
</ul>
<p>YOLO가 이미지에서 물체의 bounding box와 class를 예측하면, 로봇은 작업 대상 후보를 얻는다. 하지만 bounding box만으로 로봇이 물체를 잡을 수는 없다. Bounding box 중심은 이미지 좌표일 뿐이다. 이를 실제 물체 위치로 바꾸려면 depth 정보나 pose estimation이 필요하고, camera frame에서 robot base frame으로 변환해야 한다.</p>
<p>이렇게 얻은 물체 pose는 MoveIt의 목표 pose가 될 수 있다. 또는 물체가 장애물이라면 planning scene의 collision object로 추가될 수 있다. 이때 MoveIt은 collision checking을 수행하며 로봇이 안전하게 움직일 trajectory를 만든다.</p>
<ul>
<li><strong>Segmentation과 Planning Scene</strong></li>
</ul>
<p>Segmentation은 bounding box보다 더 정밀한 영역 정보를 제공한다. 물체의 실제 mask를 알면 물체 윤곽, 작업 가능 영역, 장애물 영역을 더 정확히 추정할 수 있다. Morphology는 segmentation mask의 작은 noise를 제거하고 구멍을 메워 더 안정적인 mask를 만든다.</p>
<p>이 mask 정보는 depth와 결합되어 3D obstacle이나 object region으로 변환될 수 있다. 이후 planning scene에 반영하면 MoveIt은 해당 영역을 피하거나 목표 대상으로 사용할 수 있다.</p>
<ul>
<li><strong>ROS2의 역할</strong></li>
</ul>
<p>ROS2는 perception 결과를 시스템 안에서 전달한다. Camera node는 image topic을 publish하고, perception node는 image를 subscribe해 detection result나 segmentation mask를 publish한다. Planning node는 이 결과를 subscribe해 목표 pose나 collision object를 만든다.</p>
<p>Service는 특정 inference 요청이나 상태 조회에 사용할 수 있고, action은 perception 기반 작업 목표를 장기 수행으로 관리할 수 있다. 예를 들어 “서랍을 찾아 접근하고 열기” 같은 작업은 detection, pose estimation, planning, control이 모두 포함된 action 구조로 생각할 수 있다.</p>
<ul>
<li><strong>Isaac Sim과 Gazebo의 역할</strong></li>
</ul>
<p>Gazebo는 로봇 모델과 controller가 물리 환경에서 동작하는지 검증하는 데 강하다. Isaac Sim은 카메라, LiDAR, IMU, contact sensor 같은 센서를 포함한 시뮬레이션과 pick-and-place 흐름을 검증하는 데 유용하다.</p>
<p>Isaac Sim 카메라 실습은 3D world point와 2D image coordinate의 관계를 보여 준다. 이 관계는 CV detection 결과를 로봇 좌표계로 연결하는 데 필요하다. Pick-and-place 실습은 물체 인식, 목표 위치 설정, gripper 제어, trajectory 실행이 하나로 이어져야 manipulation이 된다는 점을 보여 준다.</p>
<ul>
<li><strong>전체 흐름</strong></li>
</ul>
<p>로봇과 CV의 연결은 다음 순서로 이해할 수 있다.</p>
<ol>
<li>센서가 세계를 데이터로 바꾼다.</li>
<li>이미지 전처리와 CV 모델이 물체, 영역, 특징을 추출한다.</li>
<li>ROS2 topic/service/action이 결과를 시스템 안에서 전달한다.</li>
<li>TF가 camera frame, world frame, robot base frame을 연결한다.</li>
<li>MoveIt이 목표 pose와 planning scene을 바탕으로 motion planning을 수행한다.</li>
<li>ros2_control과 controller가 trajectory를 실행한다.</li>
<li>RViz, Gazebo, Isaac Sim이 상태와 실행 결과를 확인하게 한다.</li>
</ol>
<p><strong>Robot-CV 연결 실습 정리</strong></p>
<ul>
<li><strong>CV 결과는 바로 로봇 명령이 아니다</strong></li>
</ul>
<p>Depth viewer, calibration, YOLO/segmentation, MoveIt, pick-and-place 실습을 연결하면 Robot-CV pipeline의 전체 흐름이 보인다. CV는 image에서 객체 영역이나 bounding box를 찾는다. Depth camera는 해당 pixel의 depth를 제공한다. Camera intrinsic은 pixel과 depth를 camera 좌표계의 3D point로 바꾼다. Hand-eye calibration과 TF는 camera 좌표를 robot base 좌표로 바꾼다. MoveIt은 그 좌표를 목표 pose로 받아 접근/후퇴 경로를 계획한다.</p>
<ul>
<li><strong>Topic, service, action이 함께 들어가는 이유</strong></li>
</ul>
<p>Camera image와 depth image는 계속 들어오는 stream이므로 topic이다. 객체 검출 결과도 frame마다 publish되는 topic이 될 수 있다. 특정 물체의 3D pose를 계산해 달라는 요청은 service로 만들 수 있다. 로봇을 pick pose까지 움직이고 grasp sequence를 수행하는 작업은 시간이 걸리고 취소가 필요하므로 action 또는 task node가 적합하다.</p>
<ul>
<li><strong>Smart shop 예제가 로봇 task manager와 닮은 점</strong></li>
</ul>
<p>Smart shop의 <code>order_manager</code>는 재고, 할인, 결제 service를 순서대로 호출하고 결과를 log topic으로 publish한다. 로봇에서도 이와 비슷하게 task manager가 perception service, calibration/TF 변환, MoveIt planning, gripper command, log/monitoring을 조합한다. 즉 ROS2 통신 실습은 쇼핑 예제에 머물지 않고, 복잡한 로봇 작업 orchestration을 이해하는 기초가 된다.</p>
<ul>
<li><strong>Pick-and-place에서 연결되는 실제 순서</strong></li>
</ul>
<p>실제 pick-and-place pipeline은 보통 <code>image topic -&gt; detection/segmentation -&gt; depth lookup -&gt; camera coordinate -&gt; robot base coordinate -&gt; safe workspace clamp -&gt; MoveIt planning -&gt; controller execution -&gt; gripper close/open -&gt; result/log</code> 순서로 이어진다. 각 단계가 분리되어야 어느 부분이 실패했는지 찾을 수 있다. Detection이 틀린 것인지, depth가 0인지, calibration이 틀린 것인지, planning scene collision인지, controller 실행 문제인지 구분해야 한다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>CV는 로봇에게 세계를 읽어 주고, ROS2와 TF는 그 정보를 전달하고 좌표계에 맞추며, MoveIt과 controller는 그 인식 결과를 실제 로봇 행동으로 바꾼다.</p>
<h3 id="122-robot-cv-pipeline-핵심-코드-인용">1.2.2. Robot-CV Pipeline 핵심 코드 인용</h3>
<p>Robot-CV 연결은 하나의 거대한 함수가 아니라 topic, perception, depth projection, planning이 단계적으로 이어지는 구조다.</p>
<pre><code class="language-python">self.image_sub = self.create_subscription(Image, &#39;/camera/color/image_raw&#39;, self.image_callback, 10)
self.depth_sub = self.create_subscription(Image, &#39;/camera/depth/image_rect_raw&#39;, self.depth_callback, 10)
self.camera_info_sub = self.create_subscription(CameraInfo, &#39;/camera/color/camera_info&#39;, self.info_callback, 10)</code></pre>
<p>이 세 subscription은 perception pipeline의 입력 계층이다. Image만 있으면 class나 mask는 만들 수 있지만 실제 거리 정보가 부족하다. Depth와 camera info가 함께 있어야 image coordinate를 3D coordinate로 바꿀 수 있다.</p>
<pre><code class="language-python">results = self.detector(frame)
center_u = int((box.x1 + box.x2) / 2)
center_v = int((box.y1 + box.y2) / 2)
point_camera = self.project_depth_to_3d(center_u, center_v, depth)</code></pre>
<p>Detection 결과의 box center는 robot pose가 아니다. <code>project_depth_to_3d</code> 같은 단계가 있어야 pixel과 depth가 camera frame의 point로 바뀐다. 그 다음 TF 변환을 거쳐 robot base frame의 목표 위치가 된다.</p>
<pre><code class="language-python">planning_component.set_goal_state(pose_stamped_msg=pose_goal, pose_link=EE_LINK)
plan_result = planning_component.plan(parameters=plan_parameters)
robot.execute(group_name=GROUP_NAME, robot_trajectory=plan_result.trajectory, blocking=True)</code></pre>
<p>MoveIt 단계는 perception 결과를 실제 robot motion으로 바꾸는 곳이다. 여기서 실패하면 detection이 맞아도 로봇은 움직일 수 없다. 그래서 CV 학습 흐름은 image processing에서 끝나지 않고 depth, TF, MoveIt, controller까지 이어져야 로봇 과제로 완성된다.</p>
<p><strong>Click-to-pick 코드: camera topic에서 MoveIt 실행까지 이어지는 파이프라인</strong></p>
<p><code>click_pick_node.py</code>는 사용자가 영상에서 한 점을 클릭했을 때, 그 pixel이 실제 로봇 좌표와 pick 동작으로 바뀌는 전체 흐름을 보여 준다. 입력은 세 topic에서 들어온다.</p>
<pre><code class="language-python">self.create_subscription(
    CameraInfo, &quot;/camera/camera/color/camera_info&quot;,
    self._cam_info_cb, 10)
self.create_subscription(
    Image, &quot;/camera/camera/color/image_raw&quot;,
    self._color_cb, 10)
self.create_subscription(
    Image, &quot;/camera/camera/aligned_depth_to_color/image_raw&quot;,
    self._depth_cb, 10)</code></pre>
<pre><code class="language-python">def _cam_info_cb(self, msg):
    self.intrinsics = {
        &quot;fx&quot;: msg.k[0], &quot;fy&quot;: msg.k[4],
        &quot;ppx&quot;: msg.k[2], &quot;ppy&quot;: msg.k[5],
    }

def _color_cb(self, msg):
    self.color_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding=&quot;bgr8&quot;)

def _depth_cb(self, msg):
    self.depth_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding=&quot;passthrough&quot;)</code></pre>
<p>여기서 color image는 OpenCV 창에 표시되는 입력이고, depth image는 클릭한 pixel의 거리이며, camera info는 pixel을 3D ray로 복원하는 내부 파라미터다. <code>rclpy.spin_once()</code>가 반복문 안에서 돌기 때문에 이 세 callback이 계속 실행되고 최신 frame이 node 내부 변수에 저장된다.</p>
<pre><code class="language-python">while rclpy.ok():
    rclpy.spin_once(self, timeout_sec=0.01)
    if self.color_image is None:
        continue
    cv2.imshow(window, self.color_image)</code></pre>
<p>사용자가 화면을 클릭하면 pixel 좌표 <code>(x, y)</code>에서 depth를 읽고, intrinsic을 이용해 camera frame의 3D point를 만든다.</p>
<pre><code class="language-python">z_raw = self.depth_image[y, x]
if z_raw == 0:
    self.get_logger().warn(&quot;해당 픽셀 depth=0&quot;)
    return

z_m = float(z_raw) / 1000.0 if self.depth_image.dtype == np.uint16 else float(z_raw)

fx, fy   = self.intrinsics[&quot;fx&quot;],  self.intrinsics[&quot;fy&quot;]
ppx, ppy = self.intrinsics[&quot;ppx&quot;], self.intrinsics[&quot;ppy&quot;]

cam_x = (x - ppx) * z_m / fx
cam_y = (y - ppy) * z_m / fy
cam_z = z_m</code></pre>
<p>이 단계의 출력은 아직 robot base가 아니라 camera 좌표계의 점이다. 그래서 hand-eye calibration 결과인 <code>gripper2cam</code>과 현재 end-effector pose를 이용해 base 좌표로 바꾼다.</p>
<pre><code class="language-python">def transform_to_base(self, cam_xyz_m):
    coord = np.append(np.array(cam_xyz_m, dtype=float), 1.0)
    base2ee = get_ee_matrix(self.robot)
    base2cam = base2ee @ self.gripper2cam
    return (base2cam @ coord)[:3]</code></pre>
<pre><code class="language-python">base = self.transform_to_base((cam_x, cam_y, cam_z))
bx, by, bz = float(base[0]), float(base[1]), float(base[2])
self.pick_and_place(bx, by, bz)</code></pre>
<p>따라서 이 실습의 파이프라인은 <code>camera topics -&gt; callback 저장 -&gt; OpenCV 클릭 -&gt; depth lookup -&gt; camera 3D point -&gt; hand-eye transform -&gt; base 좌표 -&gt; pick_and_place()</code>다. “이미지를 클릭했다”는 사용자 입력은 바로 robot command가 아니라, depth와 calibration을 거쳐 로봇이 이해할 수 있는 좌표로 바뀐 뒤 MoveIt 계획으로 넘어간다.</p>
<p><strong>Bar sorting 코드: 검출, depth 분류, 좌표 변환, 순차 pick-and-place</strong></p>
<p><code>bar_sort_node.py</code>는 click-to-pick보다 한 단계 더 자동화된 흐름이다. 먼저 color image에서 막대 후보를 검출하고, 각 contour 중심 pixel에서 depth를 샘플링해 길이/거리 기준으로 분류한다.</p>
<pre><code class="language-python">bars, thresh = detect_bars(self.color_image, log)
if not bars:
    log.error(&quot;contour 없음 — 중단&quot;)
    return

for b in bars:
    cx, cy = b[&quot;pixel&quot;]
    d_mm = self.sample_depth_mm(cx, cy)
    if d_mm is None:
        continue
    name, rank = classify_depth_mm(d_mm)</code></pre>
<p>Depth는 한 pixel만 읽으면 노이즈나 0 값에 흔들릴 수 있으므로, 주변 <code>5x5</code> patch의 median을 사용한다.</p>
<pre><code class="language-python">x0, x1 = max(0, px - 2), min(w, px + 3)
y0, y1 = max(0, py - 2), min(h, py + 3)
patch = self.depth_image[y0:y1, x0:x1]
valid = patch[patch &gt; 0]
if valid.size == 0:
    return None
z = float(np.median(valid))</code></pre>
<p>분류된 대상은 다시 pixel에서 base 좌표로 변환된다.</p>
<pre><code class="language-python">base = self.pixel_to_base(cx, cy)
if base is None:
    log.error(f&quot;{t[&#39;name&#39;]} 좌표 변환 실패 — 중단&quot;)
    return
bx, by, bz = float(base[0]), float(base[1]), float(base[2])
ok = self.pick_and_place(bx, by, bz, PLACE_POSITIONS[rank])</code></pre>
<p>이 흐름은 <code>color/depth/camera_info topic -&gt; contour 검출 -&gt; depth median -&gt; SHORT/MEDIUM/LONG 분류 -&gt; pixel_to_base -&gt; MoveIt pick_and_place -&gt; gripper open/close</code>로 이어진다. 여기서 CV는 막대 후보와 중심 pixel을 만들고, depth와 calibration은 그 pixel을 3D base 좌표로 바꾸며, MoveIt과 gripper는 그 좌표를 실제 작업으로 실행한다.</p>
<ul>
<li><strong>Cmd에서 Robot-CV 실습을 실행하고 관찰하는 법</strong></li>
</ul>
<p><code>dsr_practice/setup.py</code>에는 Robot-CV와 manipulation 실습을 실행하기 위한 console script가 등록되어 있다.</p>
<pre><code class="language-python">entry_points={
    &#39;console_scripts&#39;: [
        &#39;click_pick_node = dsr_practice.click_pick_node:main&#39;,
        &#39;bar_sort_node = dsr_practice.bar_sort_node:main&#39;,
        &#39;stt_node = dsr_practice.stt_node:main&#39;,
        &#39;stt_robot_control = dsr_practice.stt_robot_control:main&#39;,
        &#39;stt_pick_and_place = dsr_practice.stt_pick_and_place:main&#39;,
    ],
}</code></pre>
<p>Cmd에서 <code>click_pick_node</code>를 실행하면 node는 camera topic을 subscribe하고 OpenCV 창을 띄운다. 사용자가 창에서 pixel을 클릭하면 callback이 depth를 읽고 base 좌표로 변환한 뒤 MoveIt pick sequence를 실행한다. <code>bar_sort_node</code>는 사용자가 한 점을 클릭하는 대신 color image에서 막대 contour를 찾고, depth로 분류한 뒤 순서대로 pick-and-place를 수행한다.</p>
<pre><code class="language-bash">ros2 run dsr_practice click_pick_node
ros2 run dsr_practice bar_sort_node
ros2 topic echo /camera/camera/color/image_raw
ros2 topic echo /camera/camera/aligned_depth_to_color/image_raw</code></pre>
<p>이때 topic echo는 실제 image message가 매우 크므로 장시간 보기보다 “topic이 들어오는지 확인하는 용도”로 이해하는 것이 좋다. 핵심은 cmd에서 node 실행을 확인하고, 코드에서는 subscription callback과 <code>spin_once()</code>가 최신 RGB/depth/camera info를 받아 pick pipeline으로 넘기는 구조를 읽는 것이다.</p>
<h1 id="2-depth-카메라와-캘리브레이션">2. Depth 카메라와 캘리브레이션</h1>
<h2 id="21-depth-카메라와-캘리브레이션-기본">2.1. Depth 카메라와 캘리브레이션 기본</h2>
<h3 id="211-학습-목적">2.1.1. 학습 목적</h3>
<p>일반 RGB 카메라는 이미지의 색과 밝기 정보를 제공하지만, 로봇이 물체를 잡거나 장애물을 피하려면 3D 위치 정보가 필요하다. Depth 카메라는 각 픽셀이 카메라로부터 얼마나 떨어져 있는지 나타내는 깊이 정보를 제공한다.</p>
<p>Depth 정보가 있으면 2D 이미지에서 검출한 물체 위치를 3D 공간 위치로 바꿀 수 있다. 이 과정은 YOLO나 segmentation 결과를 로봇 motion planning으로 연결하는 데 핵심이다.</p>
<h3 id="212-rgb-depth-point-cloud">2.1.2. RGB, Depth, Point Cloud</h3>
<p>RGB 이미지는 물체의 색상과 외형을 보여 준다. Depth 이미지는 각 픽셀의 거리 값을 담는다. Depth와 camera intrinsic을 이용하면 각 픽셀을 3D point로 변환할 수 있고, 이 점들의 집합이 point cloud가 된다.</p>
<p>Point cloud는 로봇 주변의 3D 구조를 나타낸다. 물체 표면, 장애물, 작업대 높이, grasp 대상의 대략적인 위치를 추정하는 데 사용될 수 있다.</p>
<h3 id="213-카메라-내부-파라미터">2.1.3. 카메라 내부 파라미터</h3>
<p>Intrinsic parameter는 카메라 자체의 특성을 나타낸다. 초점 거리, 주점, 렌즈 왜곡 계수 등이 포함된다. Intrinsic이 있어야 이미지 픽셀 좌표를 카메라 좌표계의 ray로 바꿀 수 있다.</p>
<p>렌즈 왜곡이 있으면 직선이 휘어 보이거나 위치 계산이 틀어질 수 있다. 따라서 카메라 모델에서는 pinhole 모델이나 fisheye 모델과 함께 distortion parameter를 다룬다.</p>
<h3 id="214-외부-파라미터와-hand-eye-calibration">2.1.4. 외부 파라미터와 Hand-Eye Calibration</h3>
<p>Extrinsic parameter는 카메라가 로봇 기준 어디에 장착되어 있는지 나타낸다. 로봇이 카메라로 본 물체를 잡으려면 카메라 좌표계의 3D point를 로봇 base 좌표계로 변환해야 한다.</p>
<p>Hand-Eye Calibration은 카메라와 로봇 사이의 변환 관계를 구하는 과정이다. 카메라가 로봇 손목에 붙어 있거나 외부에 고정되어 있을 때, 체커보드 같은 기준 target을 여러 자세에서 관측해 변환 행렬을 추정한다.</p>
<h3 id="215-데이터-수집-흐름">2.1.5. 데이터 수집 흐름</h3>
<p>캘리브레이션 실습에서는 체커보드를 준비하고, 로봇을 여러 자세로 이동시키며 카메라 이미지를 수집한다. 이때 로봇 pose와 카메라에서 본 target pose를 함께 기록해야 한다. 충분히 다양한 자세에서 데이터를 모아야 변환 행렬을 안정적으로 계산할 수 있다.</p>
<p>Depth 카메라를 사용할 때는 장치 번호, pixel format, colorspace도 확인해야 한다. 잘못된 device를 사용하면 이미지가 들어오지 않거나 depth/RGB stream이 맞지 않을 수 있다.</p>
<h3 id="216-로봇cv-연결">2.1.6. 로봇/CV 연결</h3>
<p>Depth 카메라와 캘리브레이션은 CV 결과를 로봇 행동으로 바꾸는 중간 다리다. YOLO가 bounding box를 찾고, depth가 해당 위치의 거리를 제공하며, calibration과 TF가 그 점을 robot base frame으로 변환한다. 그 결과가 MoveIt의 목표 pose나 planning scene object가 된다.</p>
<h3 id="217-한-줄-정리">2.1.7. 한 줄 정리</h3>
<p>Depth 카메라와 캘리브레이션은 2D 이미지 인식 결과를 로봇이 사용할 수 있는 3D 위치 정보로 바꾸는 과정이다.</p>
<h2 id="22-depth-핵심-코드">2.2. Depth 핵심 코드</h2>
<h3 id="221-depth-카메라와-캘리브레이션-실습-정리">2.2.1. Depth 카메라와 캘리브레이션 실습 정리</h3>
<ul>
<li><strong>Depth viewer가 하는 일</strong></li>
</ul>
<p><code>depth_pkg/depth_viewer.py</code>, <code>image_viewer.py</code>, <code>depth_click_viewer.py</code>는 RealSense 같은 depth camera topic을 ROS2 node에서 받아 OpenCV로 확인하는 흐름을 보여 준다. Color image는 <code>/camera/camera/color/image_raw</code>, depth image는 <code>/camera/camera/depth/image_rect_raw</code>, camera info는 <code>/camera/camera/depth/camera_info</code>에서 들어온다.</p>
<p><code>depth_click_viewer.py</code>는 클릭한 픽셀의 depth를 읽고 camera intrinsic으로 3D camera coordinate를 계산한다. <code>CameraInfo.k</code>에서 <code>fx</code>, <code>fy</code>, <code>cx</code>, <code>cy</code>를 꺼내고, depth raw 값을 m 단위 <code>Z</code>로 바꾼 뒤 <code>X = (u - cx) * Z / fx</code>, <code>Y = (v - cy) * Z / fy</code>를 계산한다. 이 식이 중요한 이유는 이미지 픽셀 좌표가 로봇이 사용할 수 있는 3D 위치로 바뀌는 첫 단계이기 때문이다.</p>
<ul>
<li><strong>CameraInfo가 필요한 이유</strong></li>
</ul>
<p>Depth 값만 있으면 물체까지의 거리 <code>Z</code>는 알 수 있지만, 픽셀이 카메라 좌표계에서 어느 방향 ray에 해당하는지는 알 수 없다. <code>fx</code>, <code>fy</code>, <code>cx</code>, <code>cy</code>가 있어야 픽셀 <code>(u, v)</code>를 카메라 좌표계의 <code>(X, Y, Z)</code>로 복원할 수 있다. 따라서 depth topic과 camera info topic은 함께 해석해야 한다.</p>
<ul>
<li><strong>Data recording 실습의 구조</strong></li>
</ul>
<p><code>Calibration_Tutorial/data_recording.py</code>는 로봇 현재 pose와 카메라 이미지를 함께 저장한다. 코드에서는 Doosan robot node를 초기화하고 <code>get_current_posx()</code>로 현재 로봇 pose를 얻은 뒤, OpenCV <code>VideoCapture</code>로 받은 frame을 파일로 저장한다. 동시에 이미지 파일 이름과 pose 목록을 <code>calibrate_data.json</code>에 기록한다.</p>
<p>이 구조가 필요한 이유는 hand-eye calibration이 “이미지 여러 장”만으로 풀리는 문제가 아니기 때문이다. 각 이미지가 촬영된 순간의 robot pose와, 이미지 안에서 보이는 calibration target pose가 함께 있어야 카메라 좌표계와 로봇 좌표계 사이의 extrinsic transform을 추정할 수 있다. 이미지와 robot pose가 서로 다른 시점에 저장되면 calibration 결과가 흔들린다.</p>
<ul>
<li><strong>Hand-eye calibration이 연결하는 좌표계</strong></li>
</ul>
<p><code>handeye_calibration.py</code>, <code>eye2hand_calibration.py</code>, <code>realsense.py</code>, <code>test.py</code>는 카메라와 로봇 사이의 변환을 계산하고 검증하는 흐름에 해당한다. Eye-in-hand라면 카메라가 robot end-effector에 붙어 있고, eye-to-hand라면 카메라가 외부 고정 위치에 있다. 두 경우 모두 목표는 카메라가 본 3D 점을 robot base 기준 좌표로 바꾸는 변환을 얻는 것이다.</p>
<ul>
<li><strong>로봇 작업으로 이어지는 이유</strong></li>
</ul>
<p>Depth viewer에서 얻은 <code>(X, Y, Z)</code>는 아직 카메라 좌표계의 점이다. 로봇이 움직이려면 이 점을 camera frame에서 tool frame 또는 base frame으로 변환해야 한다. 이때 intrinsic calibration은 픽셀을 카메라 3D 좌표로 바꾸고, hand-eye calibration은 카메라 3D 좌표를 로봇 좌표로 바꾼다. 그래서 depth camera calibration은 CV와 MoveIt 사이의 연결부다.</p>
<h3 id="222-depth-핵심-코드-인용">2.2.2. Depth 핵심 코드 인용</h3>
<p>Depth 실습의 핵심은 color image, depth image, camera info를 따로 보지 않고 같은 perception 문제의 세 입력으로 묶는 것이다.</p>
<pre><code class="language-python">self.color_sub = self.create_subscription(Image, COLOR_IMAGE_TOPIC, self.color_image_callback, 10)
self.depth_sub = self.create_subscription(Image, DEPTH_IMAGE_TOPIC, self.depth_image_callback, 10)
self.camera_info_sub = self.create_subscription(CameraInfo, CAMERA_INFO_TOPIC, self.camera_info_callback, 10)</code></pre>
<p>Color image는 사람이 보는 장면이고, depth image는 각 pixel의 거리이며, <code>CameraInfo</code>는 pixel 좌표를 3D camera 좌표로 바꾸는 내부 파라미터다. 세 topic을 함께 받아야 “이미지에서 본 물체”를 “공간상의 점”으로 바꿀 수 있다.</p>
<pre><code class="language-python">self.fx = msg.k[0]
self.fy = msg.k[4]
self.cx = msg.k[2]
self.cy = msg.k[5]</code></pre>
<p><code>fx</code>, <code>fy</code>, <code>cx</code>, <code>cy</code>는 camera intrinsic matrix에서 나온다. <code>cx</code>, <code>cy</code>는 optical center이고, <code>fx</code>, <code>fy</code>는 pixel 단위 초점거리다. 이 값이 빠지면 같은 pixel 위치라도 실제 3D 방향을 계산할 수 없다.</p>
<pre><code class="language-python">Z = float(depth_raw) / 1000.0
X = (u_depth - self.cx) * Z / self.fx
Y = (v_depth - self.cy) * Z / self.fy</code></pre>
<p>이 세 줄이 depth camera와 robot motion planning을 연결한다. YOLO의 bounding box 중심이나 segmentation mask 중심은 처음에는 <code>(u, v)</code> pixel일 뿐이다. Depth가 <code>Z</code>를 주고 intrinsic이 <code>X</code>, <code>Y</code>를 계산하면 camera frame의 3D point가 된다. 이후 TF와 hand-eye calibration으로 robot base frame으로 변환해야 MoveIt 목표 pose나 collision object 위치로 사용할 수 있다.</p>
<h2 id="23-tf와-좌표계">2.3. TF와 좌표계</h2>
<h3 id="231-기본-개념">2.3.1. 기본 개념</h3>
<p>로봇에서 위치는 숫자 세 개로만 표현되지 않는다. 항상 “어떤 좌표계를 기준으로 한 위치인가”가 함께 필요하다. 카메라가 본 물체의 위치, 로봇 base에서 본 end-effector의 위치, world에서 본 로봇의 위치는 모두 서로 다른 frame을 기준으로 한다.</p>
<p>TF는 이 frame들 사이의 관계를 시간에 따라 관리하는 ROS의 좌표 변환 시스템이다.</p>
<h3 id="232-frame">2.3.2. Frame</h3>
<p>Frame은 좌표계의 이름이다. 로봇에는 보통 <code>base_link</code>, <code>link_1</code>, <code>link_2</code>, <code>tool0</code>, <code>camera_link</code>, <code>map</code>, <code>odom</code>, <code>world</code> 같은 frame이 있다. 각 frame은 다른 frame에 대해 위치와 회전 관계를 가진다.</p>
<p>카메라가 로봇 팔 끝에 붙어 있다면 <code>camera_link</code>는 end-effector frame에 대해 고정된 transform을 가진다. 로봇 팔이 움직이면 end-effector frame이 바뀌고, 카메라 frame도 함께 움직인다.</p>
<h3 id="233-왜-중요한가">2.3.3. 왜 중요한가</h3>
<p>TF를 이해해야 하는 이유는 perception과 control이 모두 좌표 변환에 의존하기 때문이다. 카메라 이미지에서 물체를 찾았다고 해서 로봇이 바로 잡을 수 있는 것은 아니다. 이미지 좌표를 카메라 좌표로, 카메라 좌표를 로봇 base 좌표로, 로봇 base 좌표를 planning에 사용할 목표 pose로 변환해야 한다.</p>
<p>이 과정에서 frame 관계가 틀리면 로봇은 엉뚱한 곳으로 움직인다. 따라서 TF는 단순 보조 개념이 아니라 로봇 perception과 motion planning을 연결하는 핵심이다.</p>
<h3 id="234-static-transform과-dynamic-transform">2.3.4. Static Transform과 Dynamic Transform</h3>
<p>고정된 센서 장착 위치처럼 변하지 않는 관계는 static transform으로 publish할 수 있다. 로봇 관절 움직임에 따라 계속 변하는 링크 관계는 robot state publisher와 joint state 정보를 통해 동적으로 계산된다.</p>
<p>URDF는 링크와 조인트 구조를 정의하고, TF는 그 구조가 현재 관절 상태에서 어떤 좌표 관계를 가지는지 알려 준다.</p>
<h3 id="235-perception과-tf">2.3.5. Perception과 TF</h3>
<p>카메라로 물체를 검출하면 처음 얻는 정보는 이미지 좌표계에 있다. 이 좌표는 픽셀 위치이므로 로봇이 바로 사용할 수 없다. Depth 정보나 카메라 모델을 사용해 카메라 좌표계의 3D 위치로 바꾸고, TF를 통해 robot base frame이나 world frame으로 변환해야 한다.</p>
<p>이 변환이 맞아야 MoveIt이 목표 pose를 올바르게 해석할 수 있다. 예를 들어 카메라가 로봇 팔 끝에 붙어 있다면 카메라 frame은 end-effector frame과 연결되어야 하고, end-effector frame은 로봇의 link chain을 통해 base frame과 연결되어야 한다.</p>
<h3 id="236-tf-오류의-전형적인-증상">2.3.6. TF 오류의 전형적인 증상</h3>
<p>TF가 끊기면 RViz에서 sensor data가 표시되지 않거나, fixed frame 오류가 발생할 수 있다. Frame 이름이 잘못되면 데이터가 엉뚱한 위치에 나타난다. Transform 방향을 반대로 이해하면 물체 위치가 뒤집히거나 로봇이 목표와 반대 방향으로 움직일 수 있다.</p>
<p>그래서 TF는 로봇 시스템에서 조용하지만 매우 중요한 기반이다. perception, visualization, planning이 모두 TF 위에서 좌표를 공유한다.</p>
<h3 id="237-tf-실습-정리-확인한-점">2.3.7. TF 실습 정리: 확인한 점</h3>
<p>RViz에서 TF tree를 확인하는 것은 매우 중요하다. TF tree가 끊겨 있거나 frame 이름이 잘못되어 있으면, 로봇 모델이 제대로 표시되지 않거나 sensor data가 올바른 위치에 나타나지 않는다.</p>
<p>TF 문제는 겉으로 보기에는 perception 오류나 planning 오류처럼 보일 수 있지만, 실제 원인은 좌표계 연결이 잘못된 경우가 많다.</p>
<h3 id="238-한-줄-정리">2.3.8. 한 줄 정리</h3>
<p>TF는 로봇, 센서, 물체가 서로 어떤 좌표 관계에 있는지 연결해 주는 시스템이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Robotics] 5. CNN & Object Detection 이론 정리]]></title>
            <link>https://velog.io/@jack_7711/Robotics-CNN-Object-Detection-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Robotics-CNN-Object-Detection-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 22 Jun 2026 05:12:50 GMT</pubDate>
            <description><![CDATA[<h1 id="0-전체-내용-요약과-키워드">0. 전체 내용 요약과 키워드</h1>
<p>이 문서는 컴퓨터비전이 사람이 설계한 feature에서 데이터로 학습한 feature로 확장되는 흐름을 정리한다. CNN은 convolution filter를 학습해 이미지의 지역 패턴을 추출하고, augmentation은 제한된 데이터에서 다양한 조건을 경험하게 해 일반화 성능을 높인다.</p>
<p>Object detection에서는 YOLO, anchor box, NMS, Faster R-CNN을 통해 class와 위치를 동시에 예측하는 원리를 다룬다. Semantic segmentation에서는 U-Net처럼 pixel 단위 예측을 수행하는 구조를 설명한다. ViT와 CLIP은 이미지를 patch sequence나 image-text embedding으로 확장해 foundation model 흐름과 연결된다. 로봇 관점에서는 detection과 segmentation 결과가 바로 명령이 아니라 depth, TF, MoveIt으로 이어질 perception 결과라는 점이 중요하다.</p>
<p><strong>키워드</strong>: CNN, convolution layer, pooling, activation, dropout, learning rate, data augmentation, TTA, Vision Transformer, CLIP, object detection, YOLO, bounding box, confidence, anchor box, NMS, mAP, Faster R-CNN, RPN, semantic segmentation, U-Net, encoder-decoder, skip connection, mask, perception</p>
<h1 id="1-cnn">1. CNN</h1>
<h2 id="11-cnn-기본-구조">1.1. CNN 기본 구조</h2>
<h3 id="111-학습-목적">1.1.1. 학습 목적</h3>
<p>CNN은 이미지의 공간 구조를 이용해 특징을 학습하는 대표적인 딥러닝 모델이다. 고전 영상처리에서는 사람이 edge filter나 texture filter를 설계했다면, CNN은 데이터로부터 필요한 filter를 학습한다. CV 수업에서 CNN을 배우는 이유는 이미지 분류뿐 아니라 detection, segmentation, feature extraction의 기반이 되기 때문이다.</p>
<h3 id="112-convolution-layer">1.1.2. Convolution Layer</h3>
<p>Convolution layer는 작은 kernel을 이미지 위로 이동시키며 지역 패턴을 계산한다. 초기 layer는 edge, corner, color contrast 같은 낮은 수준의 특징을 학습하고, 깊은 layer로 갈수록 객체 부분이나 class와 관련된 추상 특징을 학습한다.</p>
<p>Kernel size는 한 번에 보는 지역 범위를 결정한다. 작은 kernel은 세밀한 패턴을 잡고, layer를 여러 개 쌓으면 넓은 receptive field를 얻는다. 큰 kernel은 한 번에 넓은 영역을 보지만 parameter 수와 계산량이 늘 수 있다.</p>
<h3 id="113-pooling과-activation">1.1.3. Pooling과 Activation</h3>
<p>Activation은 모델에 비선형성을 추가한다. ReLU 같은 activation이 없으면 여러 layer를 쌓아도 선형 변환의 조합에 가까워진다. Pooling은 feature map의 공간 크기를 줄이고, 작은 위치 변화에 대한 강인성을 높인다.</p>
<p>Pooling은 정보 손실도 동반한다. Classification에서는 위치 정보를 어느 정도 줄여도 되지만, segmentation처럼 픽셀 위치가 중요한 문제에서는 downsampling으로 사라지는 위치 정보를 복원하는 구조가 필요하다. 이 점이 U-Net의 skip connection과 연결된다.</p>
<h3 id="114-dropout과-learning-rate">1.1.4. Dropout과 Learning Rate</h3>
<p>Dropout은 학습 중 일부 뉴런을 무작위로 끊어 모델이 특정 feature에 과하게 의존하지 않도록 하는 regularization 기법이다. Dropout 비율이 너무 낮으면 과적합을 충분히 막지 못하고, 너무 높으면 학습 자체가 어려워질 수 있다.</p>
<p>Learning rate는 weight update 크기를 결정한다. 너무 크면 loss가 불안정하거나 발산할 수 있고, 너무 작으면 학습이 느리거나 수렴이 어려울 수 있다. 학습률 변경 실험은 optimization 조건이 모델 성능에 얼마나 중요한지 보여 준다.</p>
<h3 id="115-detection과-segmentation으로-확장">1.1.5. Detection과 Segmentation으로 확장</h3>
<p>CNN은 classification 모델에서 끝나지 않는다. YOLO, Faster R-CNN, U-Net 같은 모델도 convolution 기반 feature extractor를 사용하거나 CNN 구조에서 출발한다. 따라서 CNN을 이해하면 object detection과 semantic segmentation의 구조를 더 잘 이해할 수 있다.</p>
<h3 id="116-cnn-실습-정리">1.1.6. CNN 실습 정리</h3>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>CNN 실습에서는 conv 깊이, kernel size, dropout 비율, learning rate를 바꿔 보는 노트북들이 확인된다. 이 실험들의 핵심은 “CNN을 실행했다”가 아니라, 구조와 hyperparameter가 결과를 어떻게 바꾸는지 비교하는 것이다.</p>
<p>Conv 깊이를 늘리면 더 복잡한 특징 표현이 가능하지만 데이터가 부족하면 과적합이 생길 수 있다. Kernel size를 바꾸면 모델이 보는 지역 범위가 달라진다. Dropout은 일반화를 돕지만 과하면 성능이 떨어질 수 있다. Learning rate는 학습 안정성을 결정한다.</p>
<ul>
<li><strong>CNN 실험에서 바꿔 보는 요소</strong></li>
</ul>
<p>CV 실습 흐름은 CNN을 단순히 실행하는 것이 아니라 layer depth, kernel size, dropout, learning rate 같은 조건을 바꾸며 결과를 비교하는 방향으로 이어진다. CNN에서 convolution layer는 지역 패턴을 feature map으로 바꾸고, pooling이나 stride는 해상도와 계산량을 줄이며, fully connected 또는 classifier head는 feature를 class prediction으로 바꾼다.</p>
<ul>
<li><strong>Kernel size와 depth가 의미하는 것</strong></li>
</ul>
<p>Kernel size가 작으면 작은 지역 패턴을 세밀하게 보고, 여러 layer를 쌓으면 receptive field가 넓어져 더 큰 구조를 이해할 수 있다. Depth가 깊어질수록 low-level edge/texture에서 high-level object part로 feature가 추상화된다. 하지만 데이터가 충분하지 않거나 정규화가 부족하면 깊은 모델은 overfitting될 수 있다.</p>
<ul>
<li><strong>Dropout과 learning rate를 비교하는 이유</strong></li>
</ul>
<p>Dropout은 학습 중 일부 neuron을 임의로 끄면서 특정 feature 조합에 과하게 의존하는 것을 줄인다. Learning rate는 weight update 크기를 정한다. 너무 크면 loss가 불안정하게 흔들리고, 너무 작으면 학습이 느리거나 local pattern에 갇힐 수 있다. 실습에서 이 값을 바꾸는 이유는 CNN 성능이 architecture뿐 아니라 학습 조건에도 크게 의존한다는 점을 확인하기 위해서다.</p>
<ul>
<li><strong>로봇 perception과 연결되는 지점</strong></li>
</ul>
<p>CNN classifier는 image 전체가 무엇인지 분류하는 데서 시작하지만, 이후 object detection과 semantic segmentation의 backbone으로 확장된다. YOLO, Faster R-CNN, U-Net 같은 모델도 결국 convolutional feature extraction을 기반으로 객체 위치나 pixel mask를 예측한다. 그래서 CNN 실습은 단독 개념이 아니라 detection/segmentation으로 가기 위한 중간 기반이다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>CNN은 convolution filter를 학습해 이미지의 지역 패턴을 계층적으로 추출하며, classification, detection, segmentation의 기반이 되는 모델이다.</p>
<h2 id="12-data-augmentation">1.2. Data Augmentation</h2>
<h3 id="121-학습-목적">1.2.1. 학습 목적</h3>
<p>Data augmentation은 학습 데이터를 인위적으로 변형해 모델이 더 다양한 입력 조건을 경험하게 만드는 방법이다. 실제 환경에서는 조명, 각도, 거리, 배경, 위치, 크기, blur가 계속 변한다. 학습 데이터가 이런 변화를 충분히 포함하지 않으면 모델은 특정 조건에만 잘 맞고 새로운 환경에서 실패할 수 있다.</p>
<p>Augmentation의 목적은 단순히 데이터 수를 늘리는 것이 아니라, 모델이 입력 변화에 더 잘 일반화하도록 만드는 것이다.</p>
<h3 id="122-대표-기법">1.2.2. 대표 기법</h3>
<p>이미지 augmentation에는 회전, 좌우 반전, 이동, crop, scale 변화, 밝기 변화, 색상 변화, noise 추가 등이 있다. 각 기법은 모델이 특정 변화에 둔감해지도록 돕는다.</p>
<p>예를 들어 좌우 반전은 객체 방향 변화에 대한 일반화를 돕고, 밝기 변화는 조명 변화에 대한 강인성을 높인다. Crop과 scale 변화는 객체가 이미지 안에서 다른 크기와 위치로 나타나는 상황을 학습하게 한다.</p>
<h3 id="123-왜-학습-분포를-넓혀야-하는가">1.2.3. 왜 학습 분포를 넓혀야 하는가</h3>
<p>모델은 학습 데이터에서 본 패턴을 기준으로 판단한다. 학습 이미지가 항상 같은 조명, 같은 배경, 같은 거리에서 찍혔다면 모델은 물체 자체보다 그 촬영 조건에 과하게 맞춰질 수 있다. 이 상태에서는 실제 환경에서 조명이 바뀌거나 물체 위치가 바뀌면 성능이 떨어진다.</p>
<p>Augmentation은 학습 데이터에 실제 환경에서 일어날 수 있는 변화를 미리 넣어 주는 방식이다. 모델이 “이 정도 회전이나 밝기 변화가 있어도 같은 class”라는 경험을 하게 만들어, 특정 픽셀 배치보다 더 본질적인 특징을 보도록 유도한다.</p>
<h3 id="124-의미-보존">1.2.4. 의미 보존</h3>
<p>Augmentation은 원래 label의 의미를 보존해야 한다. 고양이 이미지를 좌우 반전해도 고양이라는 label은 유지된다. 하지만 숫자 6을 180도 회전하면 9처럼 보일 수 있다. 의료 영상이나 방향성이 중요한 데이터에서는 단순 회전도 의미를 바꿀 수 있다.</p>
<p>따라서 augmentation은 무조건 많이 적용하는 것이 아니라, 문제의 의미를 유지하는 범위에서 설계해야 한다.</p>
<h3 id="125-강도-비교">1.2.5. 강도 비교</h3>
<p>Augmentation 강도가 약하면 일반화 효과가 부족할 수 있다. 반대로 너무 강하면 원래 데이터 분포를 깨뜨려 학습을 방해할 수 있다. 실습에서 augmentation 유무, 기법별 비교, 강도 변경을 나누어 실험한 이유는 이 균형을 확인하기 위해서다.</p>
<h3 id="126-tta">1.2.6. TTA</h3>
<p>TTA는 Test-Time Augmentation이다. 학습 때만 augmentation을 사용하는 것이 아니라, 추론할 때도 입력 이미지를 여러 방식으로 변형해 예측을 종합한다. 예를 들어 원본, 좌우 반전, crop 버전의 예측을 평균내면 특정 변환에 민감한 모델의 불안정성을 줄일 수 있다.</p>
<p>TTA는 성능을 안정화할 수 있지만 추론 시간이 늘어난다. 따라서 실시간 로봇 perception에서는 정확도와 속도 사이의 trade-off를 고려해야 한다.</p>
<h3 id="127-실험-결과를-해석하는-기준">1.2.7. 실험 결과를 해석하는 기준</h3>
<p>Augmentation 실험에서는 단순히 accuracy가 올랐는지만 보면 부족하다. 어떤 변환이 실제 데이터의 변화와 맞았는지, 너무 강한 변환으로 class 의미가 깨지지 않았는지, train 성능과 validation 성능의 차이가 줄었는지 함께 봐야 한다. Augmentation이 과적합을 줄였다면 train accuracy는 조금 낮아져도 validation 성능이 더 안정될 수 있다.</p>
<h3 id="128-로봇cv-연결">1.2.8. 로봇/CV 연결</h3>
<p>로봇 카메라는 항상 같은 조건에서 이미지를 얻지 않는다. 물체가 멀거나 가까울 수 있고, 조명이 바뀌며, 배경이 달라지고, 로봇이나 물체가 움직이며 blur가 생긴다. Augmentation은 이런 현실 조건에 대비해 perception 모델이 더 robust해지도록 돕는다.</p>
<h3 id="129-data-augmentation-실습-정리">1.2.9. Data Augmentation 실습 정리</h3>
<ul>
<li><strong>Augmentation은 데이터를 늘리는 척하는 것이 아니다</strong></li>
</ul>
<p>CV 실습 흐름에서 augmentation은 rotation, flip, crop, brightness/contrast change, noise, scale change처럼 입력 이미지를 변형해 학습 분포를 넓히는 단계다. 목적은 같은 객체가 실제 환경에서 다양한 조명, 방향, 위치, 크기로 보일 수 있다는 사실을 model이 학습하게 하는 것이다.</p>
<ul>
<li><strong>어떤 변형은 label을 보존하고 어떤 변형은 깨뜨린다</strong></li>
</ul>
<p>Classification에서는 좌우 flip이나 작은 rotation이 label을 유지하는 경우가 많다. 하지만 숫자, 방향성 표지, 비대칭 부품처럼 방향이 의미를 가지는 데이터에서는 같은 변형이 label을 깨뜨릴 수 있다. Object detection에서는 image를 crop하거나 scale할 때 bounding box 좌표도 함께 바뀌어야 한다. Segmentation에서는 mask에도 같은 geometric transform을 적용해야 한다.</p>
<ul>
<li><strong>강도를 비교해야 하는 이유</strong></li>
</ul>
<p>Augmentation 강도가 약하면 실제 환경 변화에 대한 일반화 효과가 작다. 반대로 너무 강하면 학습 데이터가 실제 문제와 다른 분포가 되어 성능이 떨어질 수 있다. 로봇 perception에서는 조명 변화, 카메라 각도, motion blur, 가림, 배경 clutter가 실제로 자주 생기므로 augmentation을 문제 상황과 맞게 설계해야 한다.</p>
<ul>
<li><strong>YOLO fine-tuning과의 연결</strong></li>
</ul>
<p>YOLO fine-tuning에서는 augmentation이 특히 중요하다. 데이터 수가 적은 특정 작업물 detection 문제에서는 모델이 배경이나 촬영 구도에 과적합되기 쉽다. 밝기, scale, translation, mosaic 같은 augmentation은 같은 물체가 여러 조건에서 나타난 것처럼 학습시키지만, 너무 강하면 bounding box 품질이나 작은 객체 인식이 나빠질 수 있다. 따라서 augmentation은 “많이 넣기”보다 실제 배치 환경을 반영해 조절해야 한다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Data augmentation은 입력 분포를 확장해 모델이 실제 환경 변화에 더 잘 일반화하도록 만드는 학습 전략이다.</p>
<h2 id="13-cnn과-augmentation-핵심-코드">1.3. CNN과 Augmentation 핵심 코드</h2>
<h3 id="131-cnn과-augmentation-핵심-코드-인용">1.3.1. CNN과 Augmentation 핵심 코드 인용</h3>
<p>CNN 실습에서 먼저 봐야 하는 것은 convolution layer가 이미지 전체를 한 번에 flatten하지 않고 작은 kernel을 이동시키며 local pattern을 학습한다는 점이다.</p>
<pre><code class="language-python">model.add(Conv2D(32, (3, 3), activation=&#39;relu&#39;, input_shape=(height, width, channels)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation=&#39;relu&#39;))
model.add(Flatten())
model.add(Dense(num_classes, activation=&#39;softmax&#39;))</code></pre>
<p><code>Conv2D</code>는 edge, texture, part pattern 같은 지역 특징을 feature map으로 만들고, <code>MaxPooling2D</code>는 위치 변화에 조금 더 둔감한 표현을 만든다. <code>Flatten</code> 이후 <code>Dense</code>는 추출된 feature를 class score로 바꾼다. 이 구조를 이해해야 YOLO, Faster R-CNN, U-Net의 backbone이 왜 convolution feature extractor에서 출발하는지 설명할 수 있다.</p>
<p>Augmentation은 모델 구조가 아니라 dataset을 확장하는 학습 조건이다.</p>
<pre><code class="language-python">train_datagen = ImageDataGenerator(
    rotation_range=20,
    width_shift_range=0.1,
    height_shift_range=0.1,
    zoom_range=0.1,
    horizontal_flip=True
)</code></pre>
<p>이 코드는 같은 class의 이미지를 회전, 이동, 확대, 반전 조건에서 다시 보이게 한다. 목적은 단순히 데이터 수를 늘리는 것이 아니라 모델이 배경, 위치, 조명, 촬영 각도에 과적합되지 않게 하는 것이다. 다만 detection이나 segmentation에서는 image만 바꾸면 안 되고 bounding box나 mask도 같은 변환을 받아야 한다. 그래서 CNN 분류 실습의 augmentation 개념은 YOLO fine-tuning에서 annotation 품질 문제로 확장된다.</p>
<h2 id="14-vision-transformer와-clip">1.4. Vision Transformer와 CLIP</h2>
<h3 id="141-vision-transformer">1.4.1. Vision Transformer</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>Vision Transformer는 이미지를 patch sequence로 나누고 Transformer 구조로 처리하는 모델이다. CNN은 convolution을 통해 지역 패턴을 쌓아 가지만, ViT는 이미지를 여러 patch로 잘라 token처럼 보고 self-attention으로 patch 간 관계를 학습한다.</p>
<ul>
<li><strong>왜 이미지를 patch로 나누는가</strong></li>
</ul>
<p>Transformer는 원래 token sequence를 처리하는 구조다. 이미지는 그 자체로는 2D grid이기 때문에 Transformer에 넣으려면 sequence 형태로 바꿔야 한다. ViT는 이미지를 일정한 크기의 patch로 자르고, 각 patch를 펼쳐 embedding vector로 만든다. 이렇게 하면 이미지가 문장의 token처럼 처리될 수 있다.</p>
<p>Patch 크기는 정보 표현 방식에 영향을 준다. Patch가 크면 sequence 길이는 짧아져 계산량은 줄지만 세밀한 지역 정보가 줄어든다. Patch가 작으면 더 세밀한 정보를 담을 수 있지만 token 수가 늘어나 attention 계산량이 커진다.</p>
<ul>
<li><strong>Patch Embedding</strong></li>
</ul>
<p>ViT의 핵심 아이디어는 이미지도 문장처럼 sequence로 볼 수 있다는 것이다. 각 patch를 embedding으로 바꾸고, positional embedding을 더해 patch의 위치 정보를 제공한다. 이후 Transformer encoder가 patch들 사이의 관계를 attention으로 계산한다.</p>
<p>Positional embedding이 필요한 이유는 Transformer 자체가 입력 token의 순서를 직접 알지 못하기 때문이다. 이미지에서는 patch가 어디에 있었는지가 의미에 큰 영향을 준다. 같은 patch 내용이라도 왼쪽 위에 있는지, 중앙에 있는지에 따라 전체 장면 해석이 달라질 수 있다.</p>
<ul>
<li><strong>CNN과의 차이</strong></li>
</ul>
<p>CNN은 지역적 inductive bias가 강하다. 가까운 픽셀 사이의 관계를 convolution으로 자연스럽게 학습한다. ViT는 attention을 통해 patch 간 관계를 직접 학습하지만, CNN보다 데이터와 pretraining 조건에 더 민감할 수 있다.</p>
<ul>
<li><strong>Attention의 의미</strong></li>
</ul>
<p>Self-attention은 각 patch가 다른 patch들과 어떤 관계를 가지는지 계산한다. CNN이 가까운 이웃 픽셀부터 차례로 정보를 넓혀 간다면, ViT는 attention을 통해 멀리 떨어진 patch 사이의 관계도 직접 볼 수 있다. 이 때문에 이미지 전체의 문맥을 보는 데 장점이 있다.</p>
<p>하지만 이미지에는 지역 구조가 강하게 존재한다. CNN은 이 구조를 convolution으로 자연스럽게 반영하지만, ViT는 patch embedding과 positional embedding, 충분한 학습 데이터를 통해 이를 배워야 한다. 그래서 ViT는 보통 대규모 pretraining과 함께 이해하는 것이 좋다.</p>
<ul>
<li><strong>수업 흐름에서의 위치</strong></li>
</ul>
<p>ViT는 고전 영상처리와 CNN 이후의 최신 CV 흐름을 보여 준다. 이미지가 단순 pixel grid가 아니라 patch sequence로 표현될 수 있고, NLP에서 쓰이던 Transformer 구조가 vision에도 적용될 수 있다는 점을 이해하게 한다.</p>
<p>수업 흐름에서 ViT는 CNN 이후 “이미지를 보는 방식이 어떻게 확장되는가”를 보여 준다. CNN은 local convolution을 쌓아 전체 정보를 모으지만, ViT는 patch 사이의 관계를 attention으로 계산한다. 이 차이는 CLIP 같은 멀티모달 모델로 이어진다.</p>
<ul>
<li><strong>로봇/CV 연결</strong></li>
</ul>
<p>로봇 perception 관점에서 ViT는 장면 전체의 관계를 이해하는 데 유용할 수 있다. 물체 하나만 보는 것이 아니라 물체들 사이의 관계, 배경, context를 함께 고려하는 방향으로 확장될 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>ViT는 이미지를 patch들의 sequence로 바꾸고 attention으로 관계를 학습하는 Transformer 기반 CV 모델이다.</p>
<p><strong>CLIP</strong></p>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>CLIP은 이미지와 텍스트를 같은 임베딩 공간에 정렬하는 멀티모달 모델이다. Image encoder와 text encoder를 함께 학습해, 관련 있는 이미지와 텍스트가 가까운 벡터가 되도록 만든다.</p>
<p>이 구조 덕분에 CLIP은 별도의 classifier를 학습하지 않아도 텍스트 prompt를 이용한 zero-shot classification을 수행할 수 있다.</p>
<ul>
<li><strong>왜 이미지와 텍스트를 함께 학습하는가</strong></li>
</ul>
<p>일반적인 이미지 분류 모델은 정해진 class label 안에서만 예측한다. 학습 때 <code>cat</code>, <code>dog</code>, <code>car</code>만 배웠다면 새로운 class를 텍스트로 지정해 바로 찾기 어렵다. CLIP은 이미지와 자연어 설명을 같은 공간에 놓기 때문에, class 이름이나 설명문을 prompt로 만들어 이미지와 비교할 수 있다.</p>
<p>이 구조는 인식 문제를 고정된 label classifier에서 이미지-텍스트 유사도 문제로 바꾼다. 그래서 학습하지 않은 class라도 텍스트로 의미를 설명할 수 있으면 zero-shot 방식으로 후보를 비교할 수 있다.</p>
<ul>
<li><strong>Zero-shot 인식</strong></li>
</ul>
<p>CLIP의 핵심은 이미지 인식이 고정된 클래스 목록에 갇히지 않는다는 점이다. 기존 classifier는 학습된 클래스 안에서만 예측할 수 있다. CLIP은 텍스트 prompt와 이미지의 유사도를 비교해 분류할 수 있다.</p>
<ul>
<li><strong>이미지-텍스트 임베딩</strong></li>
</ul>
<p>CLIP은 image encoder와 text encoder를 따로 두고, 이미지와 그에 대응되는 텍스트 설명이 같은 임베딩 공간에서 가까워지도록 학습한다. 이 구조 덕분에 “이 이미지는 어떤 class인가?”라는 문제를 “이 이미지 임베딩은 어떤 텍스트 임베딩과 가장 가까운가?”라는 문제로 바꿀 수 있다.</p>
<p>이 방식은 기존 classification과 다르다. 기존 모델은 마지막 layer가 정해진 class 개수에 맞춰져 있지만, CLIP은 텍스트 prompt를 바꾸면 새로운 class 후보를 만들 수 있다. 그래서 zero-shot 분류가 가능하다.</p>
<ul>
<li><strong>한계</strong></li>
</ul>
<p>CLIP도 완전한 해결책은 아니다. Zero-shot 성능은 prompt 설계, 이미지 품질, 도메인 차이에 영향을 받는다. 실제 로봇 환경에서는 조명, occlusion, 카메라 각도, 물체 크기 변화가 크기 때문에 추가적인 fine-tuning이나 다른 perception 기법과 결합이 필요할 수 있다.</p>
<ul>
<li><strong>로봇/CV 연결</strong></li>
</ul>
<p>CLIP을 로봇과 연결하면 의미 기반 perception으로 확장된다. 사용자가 “빨간 컵을 찾아줘”라고 말했을 때, 로봇은 단순히 사전에 학습한 class id만 보는 것이 아니라 언어 의미와 이미지 특징을 연결해야 한다. CLIP은 이런 방향의 기초가 된다.</p>
<ul>
<li><strong>YOLO와의 차이</strong></li>
</ul>
<p>YOLO는 bounding box와 class를 빠르게 예측하는 detection 모델이다. CLIP은 이미지와 텍스트의 의미적 유사도를 비교하는 모델이다. 따라서 둘의 역할은 다르다. 로봇 시스템에서는 YOLO가 물체 후보 위치를 찾고, CLIP이 텍스트 지시와 후보 이미지의 의미적 관련성을 판단하는 식으로 결합될 수 있다.</p>
<p>이런 연결은 수업에서 다룬 YOLO/foundation model 비교 흐름과도 맞닿아 있다. 전통적인 supervised detector와 foundation model 기반 인식은 서로 다른 장단점을 가지며, 실제 perception 시스템에서는 문제에 따라 조합될 수 있다.</p>
<ul>
<li><strong>실습 관점에서 보는 한계</strong></li>
</ul>
<p>CLIP은 zero-shot이 가능하지만, 항상 로봇 작업에 바로 충분한 것은 아니다. Prompt 문장에 따라 결과가 달라질 수 있고, 카메라 각도나 조명, 도메인 차이에 영향을 받을 수 있다. 또한 CLIP은 기본적으로 위치를 직접 출력하는 detector가 아니므로, 로봇이 물체를 잡으려면 detection이나 segmentation, depth estimation과 결합해야 한다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>CLIP은 이미지와 텍스트를 같은 의미 공간에 정렬해 zero-shot 인식을 가능하게 하는 멀티모달 모델이다.</p>
<h1 id="2-object-detection">2. Object Detection</h1>
<h2 id="21-object-detection-기본-구조">2.1. Object Detection 기본 구조</h2>
<h3 id="211-학습-목적">2.1.1. 학습 목적</h3>
<p>Object detection은 이미지 안에 어떤 객체가 있는지와 그 객체가 어디에 있는지를 동시에 예측하는 문제다. Classification은 이미지 전체의 class를 맞히지만, detection은 객체별 class와 위치를 함께 예측한다.</p>
<p>로봇 perception에서는 detection이 특히 중요하다. 로봇이 물체를 집거나 피하거나 접근하려면 물체가 무엇이고 이미지 안 어디에 있는지 알아야 한다.</p>
<h3 id="212-detection의-출력">2.1.2. Detection의 출력</h3>
<p>Detection 결과는 보통 class label, confidence score, bounding box로 표현된다. Class label은 객체 종류, confidence score는 예측 확신도, bounding box는 객체 위치를 나타낸다.</p>
<p>Detection 평가에서는 IoU가 중요하다. IoU는 예측 box와 정답 box가 얼마나 겹치는지 나타낸다. Box가 객체를 정확히 감싸지 못하면 class가 맞아도 좋은 detection이라고 보기 어렵다.</p>
<h3 id="213-one-stage와-two-stage">2.1.3. One-stage와 Two-stage</h3>
<p>Detection 모델은 크게 one-stage detector와 two-stage detector로 나눌 수 있다. YOLO 같은 one-stage detector는 후보 생성과 분류를 한 번에 처리해 빠르다. Faster R-CNN 같은 two-stage detector는 먼저 region proposal을 만들고, 그 후보를 분류/보정해 더 정밀한 결과를 얻는다.</p>
<p>로봇에서는 실시간성이 중요할 때 one-stage detector가 유리할 수 있다. 반면 정밀 검출이 더 중요하고 속도 여유가 있으면 two-stage detector도 고려할 수 있다.</p>
<h3 id="214-detection이-어려운-이유">2.1.4. Detection이 어려운 이유</h3>
<p>객체는 다양한 크기와 비율로 나타난다. 서로 겹치거나 일부가 가려질 수 있고, 배경과 색이 비슷할 수도 있다. 작은 객체는 feature map에서 정보가 사라지기 쉽고, 비슷한 클래스는 구분하기 어렵다.</p>
<p>따라서 detection은 모델 구조뿐 아니라 데이터셋 구성, annotation 품질, augmentation, threshold, NMS 설정까지 함께 봐야 한다.</p>
<h3 id="215-yolo-프로젝트와의-연결">2.1.5. YOLO 프로젝트와의 연결</h3>
<p>YOLO 기반 서랍 detection 프로젝트는 object detection의 실제 적용 흐름을 보여 준다. 특정 물체를 검출하기 위해 데이터셋을 구축하고, bounding box annotation을 준비하고, fine-tuning을 수행하고, 결과를 비교한다.</p>
<p>이 과정에서 detection은 단순히 모델을 불러오는 일이 아니라, 문제 정의와 데이터 품질, 평가 기준이 함께 작동하는 pipeline이라는 점을 이해하게 된다.</p>
<h3 id="216-로봇cv-연결">2.1.6. 로봇/CV 연결</h3>
<p>Detection 결과는 로봇이 행동할 대상 후보가 된다. 그러나 bounding box는 2D 이미지 좌표계 정보이므로, 실제 로봇 행동에는 depth와 TF 변환이 필요하다. Detection은 perception의 시작점이고, pose estimation과 motion planning으로 이어져야 한다.</p>
<h3 id="217-object-detection-실습-정리">2.1.7. Object Detection 실습 정리</h3>
<ul>
<li><strong>Detection은 classification보다 출력이 복잡하다</strong></li>
</ul>
<p>Object detection은 이미지 안에 무엇이 있는지만 말하지 않고, 어디에 있는지도 함께 예측한다. 따라서 출력은 class label 하나가 아니라 bounding box, class score, confidence, 중복 후보 제거 결과로 구성된다. YOLO 실습 결과를 볼 때는 box가 물체를 얼마나 정확히 감싸는지, 작은 물체를 놓쳤는지, 배경을 물체로 잘못 봤는지, 중복 box가 남았는지를 함께 확인해야 한다.</p>
<ul>
<li><strong>Annotation이 곧 학습 기준이다</strong></li>
</ul>
<p>Detection dataset에서는 annotation 품질이 모델 성능을 직접 좌우한다. Bounding box가 실제 물체보다 크게 그려지면 모델은 배경까지 객체의 일부로 학습하고, 너무 작게 그려지면 물체 일부만 보고 학습한다. 같은 객체 class 이름이 흔들리면 class probability가 불안정해진다. 그래서 fine-tuning 과제에서는 모델 구조보다 dataset 구축과 label 검토가 먼저다.</p>
<ul>
<li><strong>로봇 perception에서 detection 결과가 쓰이는 방식</strong></li>
</ul>
<p>로봇이 물체를 집으려면 detection box 중심만으로는 부족하다. Box center pixel에 depth를 결합해 camera 좌표계의 3D point를 만들고, hand-eye calibration과 TF를 통해 robot base frame으로 바꿔야 한다. 이후 MoveIt이 접근 pose와 grasp pose를 계획한다. Detection은 작업 대상 후보를 찾는 단계이고, 실제 motion은 depth, calibration, planning과 연결되어야 한다.</p>
<ul>
<li><strong>실패 사례를 기록해야 하는 이유</strong></li>
</ul>
<p>Detection 실습 정리는 mAP나 성공 이미지 몇 장만으로 끝나면 부족하다. False positive, false negative, 중복 box, 가림, 조명 변화, 작은 객체, 비슷한 배경 texture에서 실패한 사례를 기록해야 한다. 로봇 시스템에서는 한 번의 오검출이 잘못된 pick target이나 충돌 위험으로 이어질 수 있기 때문이다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Object detection은 객체의 class와 위치를 동시에 예측해 로봇이 주변 물체를 행동 대상으로 인식하게 하는 핵심 CV 기술이다.</p>
<h2 id="22-yolo와-핵심-코드">2.2. YOLO와 핵심 코드</h2>
<h3 id="221-yolo">2.2.1. YOLO</h3>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>YOLO는 실시간 object detection을 위해 널리 쓰이는 one-stage detector다. 로봇이 카메라로 주변 환경을 보고 물체를 찾으려면, 이미지 안에 무엇이 있고 어디에 있는지 빠르게 알아야 한다. YOLO는 class prediction과 bounding box regression을 한 번의 forward pass에서 함께 수행하기 때문에 실시간 perception과 잘 맞는다.</p>
<p>수업과 과제에서는 YOLO11 기반 서랍 detection, fine-tuning, foundation model 비교 흐름이 확인된다. 이 흐름은 YOLO를 단순 실행하는 것이 아니라, 데이터셋 구축, 학습, 평가, 결과 해석까지 detection pipeline 전체를 이해하는 방향이다.</p>
<ul>
<li><strong>Object Detection의 문제 구조</strong></li>
</ul>
<p>Object detection은 classification과 localization이 결합된 문제다. Classification은 이미지나 객체가 어떤 class인지 맞히는 것이고, localization은 객체가 이미지 안의 어디에 있는지 bounding box로 표현하는 것이다. YOLO는 이 두 문제를 동시에 처리한다.</p>
<p>Detection 결과는 보통 class label, confidence score, bounding box로 표현된다. Confidence가 높다고 항상 좋은 detection은 아니다. Box 위치가 부정확하면 IoU가 낮을 수 있고, threshold 설정에 따라 false positive나 false negative가 달라진다.</p>
<ul>
<li><strong>YOLO의 기본 흐름</strong></li>
</ul>
<p>YOLO는 이미지를 feature map 단위로 처리하고, 각 위치에서 객체 후보를 예측한다. 모델은 bounding box 좌표, objectness score, class probability를 출력한다. 이후 confidence threshold와 NMS를 통해 최종 detection 결과를 정리한다.</p>
<p>이 구조는 빠르다는 장점이 있지만, 작은 객체나 겹친 객체, 학습 데이터에 부족한 환경에서는 오류가 생길 수 있다. 그래서 데이터셋 품질과 annotation 품질이 매우 중요하다.</p>
<ul>
<li><strong>Fine-Tuning</strong></li>
</ul>
<p>YOLO fine-tuning은 기존 pretrained model을 특정 detection task에 맞게 다시 학습시키는 과정이다. 서랍 detection처럼 특정 물체를 찾는 문제에서는 일반 객체 데이터만으로는 충분하지 않을 수 있다. 다양한 각도, 거리, 조명, 배경에서 서랍 이미지가 필요하고, bounding box annotation이 정확해야 한다.</p>
<p>Fine-tuning에서 중요한 것은 단순히 학습을 돌리는 것이 아니라 데이터 분포를 이해하는 것이다. 특정 각도나 배경에 치우친 데이터로 학습하면 모델은 그 조건에서는 잘 맞지만 새로운 환경에서는 실패할 수 있다.</p>
<ul>
<li><strong>결과 해석 기준</strong></li>
</ul>
<p>YOLO 결과를 볼 때는 detection box가 정확히 객체를 감싸는지, confidence가 적절한지, 누락된 객체가 있는지, 중복 box가 많은지 확인해야 한다. 또한 NMS threshold와 confidence threshold가 결과에 미치는 영향도 봐야 한다.</p>
<p>서랍 detection 과제의 의미는 모델을 사용했다는 데 있지 않고, 특정 물체 인식 문제에서 데이터셋 구축과 fine-tuning, foundation model 비교를 통해 detection 성능을 해석했다는 데 있다.</p>
<p><strong>YOLO 핵심 코드 인용</strong></p>
<p>YOLO fine-tuning 실습은 pretrained detector를 불러오고, dataset yaml과 threshold를 명시한 뒤, 결과를 비교하는 흐름으로 읽어야 한다.</p>
<pre><code class="language-python">from ultralytics import YOLO

PUBLIC_WEIGHT = &quot;yolo11n.pt&quot;
MY_WEIGHT = &quot;./checkpoint/yolo_v11/Dice/20260522/yolo11n_dr_di_v4.pt&quot;

CONF_THR = 0.25
IOU_THR = 0.5
FOUNDATION_CONF_THR = 0.10</code></pre>
<p><code>PUBLIC_WEIGHT</code>는 일반 pretrained model이고, <code>MY_WEIGHT</code>는 과제 dataset에 맞게 fine-tuning한 weight다. 둘을 비교해야 “모델이 좋아졌다”가 아니라 “서랍 detection이라는 특정 문제에 맞게 무엇이 개선되었는지”를 볼 수 있다. <code>CONF_THR</code>는 낮은 confidence 후보를 버리는 기준이고, <code>IOU_THR</code>는 NMS에서 겹치는 box를 얼마나 강하게 제거할지 정한다.</p>
<p>Dataset 준비 코드에서는 image만이 아니라 <code>data.yaml</code>이 중요하다.</p>
<pre><code class="language-python">with zipfile.ZipFile(DATA_ZIP, &quot;r&quot;) as zip_ref:
    zip_ref.extractall(EXTRACT_DIR)

yaml_candidates = glob.glob(
    os.path.join(EXTRACT_DIR, &quot;**&quot;, &quot;data.yaml&quot;),
    recursive=True
)</code></pre>
<p>Detection dataset은 image folder만 있으면 충분하지 않다. <code>data.yaml</code>은 train/validation 경로와 class 이름을 연결하고, 각 image에는 bounding box annotation이 대응되어야 한다. Box가 물체보다 크거나 작으면 localization 기준이 흔들리고, class label이 틀리면 confidence와 confusion이 나빠진다.</p>
<p>YOLO 결과를 로봇에 연결할 때는 box가 끝이 아니라 시작이다.</p>
<pre><code class="language-python">results = model(image, conf=CONF_THR, iou=IOU_THR)
boxes = results[0].boxes
center_u = int((x1 + x2) / 2)
center_v = int((y1 + y2) / 2)</code></pre>
<p><code>center_u</code>, <code>center_v</code>는 image coordinate다. 로봇이 잡을 위치가 되려면 depth lookup으로 <code>Z</code>를 얻고, camera intrinsic으로 3D point를 만들고, TF로 robot base frame으로 변환해야 한다. 따라서 object detection은 perception pipeline의 출발점이지 pick pose 자체가 아니다.</p>
<p><strong>Anchor Box와 NMS</strong></p>
<p>Anchor box는 다양한 크기와 비율의 객체 후보를 표현하기 위한 사전 박스 구조다. NMS는 하나의 객체에 대해 여러 box가 예측되었을 때 중복 box를 제거해 최종 결과를 정리한다.</p>
<p>NMS threshold가 낮으면 겹치는 box가 많이 제거되어 중복은 줄지만 가까운 객체가 함께 사라질 수 있다. Threshold가 높으면 중복 box가 남을 수 있다. 따라서 YOLO 결과 해석에는 모델 출력뿐 아니라 후처리 기준도 포함된다.</p>
<ul>
<li><strong>로봇/CV 연결</strong></li>
</ul>
<p>YOLO는 로봇 perception에서 물체 후보를 찾는 출발점이 될 수 있다. 하지만 bounding box는 이미지 좌표계의 정보다. 로봇이 실제로 물체를 집으려면 bounding box 중심을 3D 위치로 바꾸고, camera frame에서 robot base frame으로 변환해야 한다. 이때 depth 정보, camera calibration, TF가 필요하다.</p>
<p>따라서 YOLO는 로봇 행동의 끝이 아니라 perception pipeline의 시작이다. YOLO가 “무엇이 어디쯤 보인다”를 알려 주면, 이후 pose estimation과 MoveIt planning을 통해 로봇이 실제 행동으로 옮길 수 있다.</p>
<p><strong>YOLO와 Detection 실습 정리</strong></p>
<ul>
<li><strong>YOLO 실습에서 봐야 하는 출력</strong></li>
</ul>
<p>YOLO 계열 실습은 모델이 이미지를 보고 class label만 맞히는 문제가 아니라 bounding box, confidence score, class probability를 함께 출력하는 문제다. 하나의 물체에 여러 후보 box가 생길 수 있고, 후처리 단계에서 confidence threshold와 NMS를 적용해 최종 detection을 만든다. 따라서 결과 이미지를 볼 때는 “맞았다/틀렸다”보다 box 위치, box 크기, 중복 box, 놓친 객체, 잘못된 class를 함께 봐야 한다.</p>
<ul>
<li><strong>Dataset 구축이 성능을 좌우하는 이유</strong></li>
</ul>
<p>YOLO fine-tuning 과제 흐름에서는 dataset이 핵심이다. Detection dataset은 image만 모으면 끝이 아니라 각 객체의 bounding box와 class label이 정확해야 한다. Box가 물체보다 지나치게 크거나 작으면 모델은 잘못된 위치 기준을 학습한다. Class label이 흔들리면 같은 시각 패턴을 다른 class로 학습해 confidence가 낮아진다.</p>
<ul>
<li><strong>Anchor/NMS와 연결해서 해석하기</strong></li>
</ul>
<p>YOLO는 grid 또는 feature map 위치마다 여러 candidate box를 예측하고, 후처리에서 NMS가 겹치는 box를 정리한다. NMS threshold가 낮으면 가까운 객체 중 하나가 사라질 수 있고, threshold가 높으면 중복 box가 남을 수 있다. Confidence threshold가 높으면 오검출은 줄지만 작은 객체나 흐린 객체를 놓칠 수 있다. 그래서 detection 결과 해석에는 모델 구조뿐 아니라 후처리 조건이 함께 들어가야 한다.</p>
<ul>
<li><strong>로봇 작업으로 연결되는 지점</strong></li>
</ul>
<p>YOLO가 반환한 bounding box는 로봇에게 바로 pick pose가 되지 않는다. Box center pixel을 depth camera로 3D point로 바꾸고, camera calibration과 TF를 거쳐 robot base frame으로 변환해야 한다. 그 다음 MoveIt이 접근 pose와 grasp pose를 계획한다. 즉 YOLO는 “어디에 물체가 보이는가”를 알려 주고, depth/TF/MoveIt이 “로봇이 어디로 어떻게 움직일 것인가”를 완성한다.</p>
<ul>
<li><strong>실습 결과를 교과서적으로 정리하는 기준</strong></li>
</ul>
<p>YOLO 실습을 정리할 때는 model name이나 실행 명령만 적으면 부족하다. Dataset 구성, annotation 품질, train/validation 분리, augmentation, confidence threshold, NMS threshold, false positive/false negative 사례, 작은 객체 성능, 가림과 조명 변화에 대한 실패 사례까지 함께 적어야 한다. 그래야 detection이 단순 모델 호출이 아니라 perception pipeline이라는 점이 드러난다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>YOLO는 이미지에서 객체의 class와 bounding box를 빠르게 예측하는 one-stage detector이며, 로봇 perception에서 작업 대상 후보를 찾는 핵심 도구가 될 수 있다.</p>
<h2 id="23-anchor-box와-nms">2.3. Anchor Box와 NMS</h2>
<h3 id="231-anchor-box와-nms-상세">2.3.1. Anchor Box와 NMS 상세</h3>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>Object detection 모델의 결과는 단순히 “box 하나”가 아니다. 모델은 이미지의 여러 위치에서 여러 크기와 비율의 box 후보를 만들고, 각 후보에 대해 객체 여부와 class를 예측한다. 이 과정에서 후보를 어떻게 만들지와 중복 후보를 어떻게 정리할지가 detection 성능을 크게 바꾼다.</p>
<p>Anchor box는 후보를 만드는 방식이고, NMS는 후보를 정리하는 방식이다. YOLO 결과를 해석하려면 모델 구조뿐 아니라 이 두 후처리/후보 개념을 함께 이해해야 한다.</p>
<ul>
<li><strong>Anchor Box</strong></li>
</ul>
<p>Anchor box는 object detection에서 다양한 크기와 비율의 객체를 예측하기 위한 사전 박스 구조다. 이미지 안의 객체는 작을 수도 크고, 가로로 길 수도 세로로 길 수도 있다. Anchor box는 이런 다양한 형태를 미리 가정한 후보 박스를 제공한다.</p>
<p>Anchor 기반 detector는 각 위치에서 여러 anchor box를 기준으로 실제 객체와의 차이를 예측한다. 모델은 박스를 처음부터 완전히 새로 만드는 것이 아니라, anchor box를 얼마나 이동하고 크기를 바꿀지 regression한다.</p>
<p>Anchor box를 이해하면 detection이 단순히 “객체 중심점 하나를 찍는 문제”가 아니라는 점이 보인다. 모델은 여러 위치와 여러 비율의 후보를 동시에 고려하고, 그중 실제 객체와 잘 맞는 후보를 조정한다. 작은 물체, 길쭉한 물체, 정사각형에 가까운 물체가 모두 같은 이미지 안에 있을 수 있기 때문에 anchor의 크기와 비율은 detection 성능에 영향을 준다.</p>
<p>YOLO 계열 모델을 해석할 때 anchor나 anchor-free 구조의 차이를 모두 깊게 구현할 필요는 없더라도, detection 모델이 다양한 객체 크기를 어떻게 다루는지 이해하는 것이 중요하다. 특히 서랍 detection처럼 특정 물체를 찾는 경우, 데이터셋 안 객체 크기와 비율이 학습 결과에 영향을 줄 수 있다.</p>
<ul>
<li><strong>NMS</strong></li>
</ul>
<p>NMS는 Non-Maximum Suppression의 약자로, 중복 detection 결과를 제거하는 후처리 과정이다. Detection 모델은 하나의 객체에 대해 여러 bounding box를 예측할 수 있다.</p>
<p>NMS는 confidence가 높은 박스를 먼저 선택하고, 그 박스와 IoU가 높은 다른 박스를 제거한다. 이 과정을 반복해 최종 박스 집합을 만든다.</p>
<p>NMS를 적용하지 않으면 하나의 객체 주변에 여러 개의 box가 남을 수 있다. 반대로 NMS가 너무 강하면 실제로는 가까이 붙어 있는 서로 다른 객체 중 하나가 지워질 수 있다. 그래서 NMS는 단순 정리 과정이 아니라 detection 결과 품질을 결정하는 중요한 후처리다.</p>
<ul>
<li><strong>Threshold의 영향</strong></li>
</ul>
<p>NMS threshold는 결과에 큰 영향을 준다. Threshold가 낮으면 조금만 겹쳐도 박스가 제거되므로 중복은 줄지만 가까운 객체가 함께 사라질 수 있다. Threshold가 높으면 중복 박스가 많이 남을 수 있다.</p>
<p><strong>Anchor와 NMS 실습 정리</strong></p>
<p>Anchor box와 NMS를 이해하면 YOLO 결과에서 왜 박스가 여러 개 나오거나, 왜 어떤 객체가 사라지는지 설명할 수 있다. Detection은 모델 출력만으로 끝나지 않고 후보 생성과 후처리까지 포함하는 pipeline이다.</p>
<p>YOLO 결과를 볼 때 confidence가 높은 box만 확인하면 부족하다. 같은 객체에 여러 box가 겹쳐 있는지, 가까운 객체가 NMS 때문에 하나로 합쳐졌는지, 작은 객체의 box가 안정적으로 남는지 함께 봐야 한다. 이 해석 능력이 있어야 detection 결과를 로봇 perception에 사용할 수 있다.</p>
<p>로봇에서 NMS 결과는 실제 행동 대상 선택으로 이어질 수 있다. 잘못된 중복 제거로 목표 물체가 사라지면 로봇은 잡아야 할 물체를 놓칠 수 있고, 중복 box가 남으면 같은 물체를 여러 대상으로 착각할 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Anchor box는 후보 박스를 만들고, NMS는 중복 박스를 제거해 detection 결과를 정리한다.</p>
<h2 id="24-faster-r-cnn">2.4. Faster R-CNN</h2>
<h3 id="241-기본-개념">2.4.1. 기본 개념</h3>
<p>Faster R-CNN은 two-stage object detector다. 첫 번째 단계에서는 Region Proposal Network가 객체가 있을 만한 후보 영역을 만든다. 두 번째 단계에서는 각 후보 영역을 분류하고 bounding box를 보정한다.</p>
<p>이 구조는 YOLO 같은 one-stage detector보다 느릴 수 있지만, 후보 영역을 정교하게 다루기 때문에 높은 정확도를 기대할 수 있다.</p>
<h3 id="242-왜-두-단계로-나누는가">2.4.2. 왜 두 단계로 나누는가</h3>
<p>Object detection은 “어디에 객체가 있을 가능성이 있는가”와 “그 객체가 무엇인가”라는 두 질문을 동시에 풀어야 한다. Faster R-CNN은 이 두 질문을 명시적으로 나눈다. RPN은 이미지 전체에서 객체 후보 영역을 찾고, detection head는 그 후보를 class로 분류하고 box를 보정한다.</p>
<p>이렇게 나누면 모델은 모든 위치와 모든 class를 한 번에 직접 맞히기보다, 먼저 objectness가 높은 영역에 집중할 수 있다. 후보 영역을 바탕으로 더 세밀한 feature를 뽑아 분류하므로 정밀한 detection에 유리하다.</p>
<h3 id="243-rpn">2.4.3. RPN</h3>
<p>Faster R-CNN의 핵심은 region proposal을 모델 안으로 통합했다는 점이다. 이전의 R-CNN 계열은 외부 알고리즘으로 후보 영역을 만들었지만, Faster R-CNN은 RPN을 통해 후보 생성도 학습 가능한 구조로 만들었다.</p>
<p>RPN은 feature map 위에서 anchor를 기준으로 objectness와 box regression을 예측한다.</p>
<p>RPN의 objectness는 “이 anchor 주변에 객체가 있을 가능성이 있는가”를 의미한다. Box regression은 anchor를 실제 객체 위치에 더 맞게 이동하고 크기를 조정하는 과정이다. 이렇게 만들어진 proposal은 다음 단계에서 RoI 단위 feature로 변환되어 class prediction과 box refinement에 사용된다.</p>
<h3 id="244-yolo와의-비교">2.4.4. YOLO와의 비교</h3>
<p>YOLO는 빠른 실시간 detection에 강하고, Faster R-CNN은 후보 영역을 더 정밀하게 다루는 방향에 가깝다. 로봇 시스템에서는 실시간성이 중요하면 YOLO 계열이 유리할 수 있고, 정밀 검출이 더 중요하면 two-stage detector를 고려할 수 있다.</p>
<h3 id="245-detection-학습-흐름에서의-의미">2.4.5. Detection 학습 흐름에서의 의미</h3>
<p>Faster R-CNN은 object detection을 두 단계로 나누어 생각하게 해 준다. 첫 단계는 “어디에 객체가 있을 가능성이 높은가”를 찾는 것이고, 두 번째 단계는 “그 후보가 어떤 객체이며 box를 어떻게 보정해야 하는가”를 판단하는 것이다. 이 구조를 이해하면 detection이 단순 classification이 아니라 위치 후보 생성과 class 예측, box regression이 결합된 문제라는 점이 분명해진다.</p>
<p>YOLO를 주로 실습했더라도 Faster R-CNN을 함께 정리하는 이유는 detection 모델의 설계 철학을 비교하기 위해서다. YOLO는 속도를 위해 한 번에 예측하고, Faster R-CNN은 후보를 먼저 만들고 정밀하게 다듬는다. 이 차이는 실제 프로젝트에서 모델 선택 기준이 된다.</p>
<h3 id="246-실습-관점에서-해석하는-법">2.4.6. 실습 관점에서 해석하는 법</h3>
<p>Faster R-CNN을 직접 구현하지 않았더라도, YOLO 실험 결과를 해석할 때 two-stage detector와 비교하면 모델 선택 기준이 분명해진다. 서랍 detection처럼 특정 물체를 빠르게 찾아야 하는 문제에서는 YOLO의 속도가 장점이 된다. 반면 작은 객체나 겹친 객체를 더 정밀하게 찾는 문제가 중심이라면 후보 영역 기반 접근이 왜 등장했는지 이해할 수 있다.</p>
<h3 id="247-한-줄-정리">2.4.7. 한 줄 정리</h3>
<p>Faster R-CNN은 후보 영역 생성과 분류/보정을 나누어 정밀한 객체 검출을 수행하는 two-stage detector다.</p>
<h1 id="3-semantic-segmentation">3. Semantic Segmentation</h1>
<h2 id="31-semantic-segmentation-기본-구조">3.1. Semantic Segmentation 기본 구조</h2>
<h3 id="311-기본-개념">3.1.1. 기본 개념</h3>
<p>Semantic segmentation은 이미지의 각 픽셀에 클래스 라벨을 부여하는 문제다. Object detection이 객체를 bounding box로 감싸는 것이라면, semantic segmentation은 객체의 영역을 픽셀 단위로 분리한다.</p>
<p>예를 들어 이미지의 각 픽셀이 사람, 도로, 벽, 물체, 배경 중 무엇인지 예측한다.</p>
<h3 id="312-왜-픽셀-단위-예측이-필요한가">3.1.2. 왜 픽셀 단위 예측이 필요한가</h3>
<p>Bounding box는 객체가 있는 대략적인 위치를 알려 주지만, 객체의 실제 모양을 알려 주지는 않는다. Box 안에는 배경 픽셀도 포함될 수 있고, 객체가 비정형 모양이면 box 표현은 더 거칠어진다. Semantic segmentation은 각 픽셀의 class를 예측하므로 물체의 윤곽과 영역을 더 정확하게 표현할 수 있다.</p>
<p>로봇이 물체를 잡거나 장애물을 피할 때는 대략적인 사각형보다 실제 점유 영역이 더 유용한 경우가 많다. 특히 테이블 위 여러 물체가 붙어 있거나, 얇고 긴 물체처럼 box가 많은 배경을 포함하는 경우 segmentation mask가 더 직접적인 정보를 준다.</p>
<h3 id="313-왜-어려운가">3.1.3. 왜 어려운가</h3>
<p>Semantic segmentation은 위치 정보가 매우 중요하다. Classification에서는 이미지 전체가 어떤 클래스인지 맞히면 되지만, segmentation에서는 각 픽셀의 클래스가 맞아야 한다.</p>
<p>따라서 downsampling으로 얻은 추상적 의미 정보와 원래 이미지의 세밀한 위치 정보를 함께 보존해야 한다.</p>
<p>Segmentation 모델은 문맥과 위치를 동시에 다뤄야 한다. 큰 문맥을 보려면 receptive field가 넓어져야 하고, 그러려면 downsampling이 필요하다. 하지만 downsampling은 경계와 작은 객체 정보를 흐리게 만든다. 그래서 segmentation 모델은 의미 정보를 얻는 encoder와 해상도를 복원하는 decoder, 또는 skip connection 같은 구조를 사용한다.</p>
<h3 id="314-로봇cv-연결">3.1.4. 로봇/CV 연결</h3>
<p>Segmentation 결과는 로봇 perception에서 유용하다. Bounding box는 객체의 대략적인 위치를 알려 주지만, segmentation mask는 객체의 실제 영역과 모양을 더 잘 나타낸다.</p>
<p>Grasping, obstacle avoidance, scene understanding에서는 픽셀 단위 영역 정보가 중요할 수 있다.</p>
<h3 id="315-detection과의-차이">3.1.5. Detection과의 차이</h3>
<p>Object detection은 객체를 사각형 box로 표현한다. 이 방식은 빠르고 간단하지만, 객체의 정확한 윤곽을 알 수 없다. 반면 semantic segmentation은 각 픽셀의 class를 예측하므로 객체의 실제 영역을 더 세밀하게 표현한다.</p>
<p>예를 들어 로봇이 물체를 잡아야 하는 상황에서 bounding box만 있으면 box 안의 배경도 함께 포함될 수 있다. Segmentation mask가 있으면 실제 물체 영역을 더 정확히 알 수 있어 grasp point 추정이나 장애물 영역 계산에 유리하다.</p>
<h3 id="316-u-net과의-연결">3.1.6. U-Net과의 연결</h3>
<p>Semantic segmentation에서는 해상도 복원이 중요하다. CNN처럼 downsampling을 반복하면 의미 정보는 풍부해지지만 위치 정보가 줄어든다. U-Net은 encoder-decoder 구조와 skip connection을 통해 이 문제를 해결하려고 한다. 따라서 semantic segmentation을 이해하면 U-Net 구조가 왜 필요한지도 자연스럽게 이해할 수 있다.</p>
<h3 id="317-semantic-segmentation-실습-정리-결과-해석-기준">3.1.7. Semantic Segmentation 실습 정리: 결과 해석 기준</h3>
<p>Segmentation 결과는 accuracy 하나로만 판단하기 어렵다. 객체 경계가 얼마나 잘 맞는지, 작은 객체가 사라지지 않았는지, 배경과 전경이 섞이지 않았는지, mask에 구멍이나 잡음이 남아 있는지 봐야 한다. 고전 segmentation 실습에서 thresholding, hole filling, morphology를 함께 다룬 이유도 이런 후처리 문제가 픽셀 단위 예측에서 계속 등장하기 때문이다.</p>
<h3 id="318-한-줄-정리">3.1.8. 한 줄 정리</h3>
<p>Semantic segmentation은 이미지의 각 픽셀을 의미 있는 클래스로 분류해 객체의 실제 영역을 파악하는 기술이다.</p>
<h2 id="32-u-net-구조와-핵심-코드">3.2. U-Net 구조와 핵심 코드</h2>
<h3 id="321-u-net">3.2.1. U-Net</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>U-Net은 semantic segmentation에서 널리 사용되는 encoder-decoder 구조의 네트워크다. Encoder는 이미지를 점점 작게 만들며 추상적인 feature를 추출하고, decoder는 feature를 다시 원래 해상도에 가깝게 복원해 픽셀 단위 예측을 만든다.</p>
<ul>
<li><strong>왜 U자 구조인가</strong></li>
</ul>
<p>U-Net이라는 이름은 encoder가 해상도를 줄이며 내려가고, decoder가 해상도를 다시 올리며 올라가는 구조가 U자 형태를 가지기 때문에 붙었다. 왼쪽 경로는 feature를 압축하고 의미 정보를 얻는 역할을 하고, 오른쪽 경로는 압축된 정보를 다시 픽셀 위치에 맞게 복원하는 역할을 한다.</p>
<p>Segmentation은 classification과 달리 최종적으로 원본 이미지와 같은 공간 해상도의 mask를 만들어야 한다. 그래서 단순히 feature를 압축해 class 하나를 예측하는 구조로는 부족하고, 압축된 정보를 다시 이미지 공간으로 펼치는 decoder가 필요하다.</p>
<ul>
<li><strong>Encoder-Decoder 구조</strong></li>
</ul>
<p>Encoder는 pooling이나 stride convolution을 통해 공간 해상도를 줄이고 더 추상적인 feature를 얻는다. Decoder는 upsampling을 통해 해상도를 복원한다. 이 구조는 의미 정보와 위치 정보를 함께 다루기 위한 기본 틀이다.</p>
<p>Encoder가 깊어질수록 모델은 더 넓은 문맥을 본다. 예를 들어 특정 픽셀이 물체인지 배경인지 판단하려면 주변의 큰 형태와 문맥이 필요할 수 있다. Decoder는 이 의미 정보를 다시 픽셀 단위 예측으로 바꾸는데, 이때 위치 정보가 충분하지 않으면 mask 경계가 흐려질 수 있다.</p>
<ul>
<li><strong>Skip Connection</strong></li>
</ul>
<p>U-Net의 핵심은 skip connection이다. Encoder의 각 단계에서 얻은 feature를 decoder의 대응 단계로 전달한다. 이를 통해 decoder는 깊은 layer의 의미 정보뿐 아니라 얕은 layer의 위치 정보를 함께 사용할 수 있다.</p>
<p>Segmentation에서는 객체가 무엇인지뿐 아니라 정확히 어디에 있는지가 중요하므로 skip connection이 큰 역할을 한다.</p>
<ul>
<li><strong>로봇/CV 연결</strong></li>
</ul>
<p>U-Net은 의료 영상 segmentation에서 유명해졌지만, 구조 자체는 다양한 pixel-wise prediction 문제에 응용된다. 로봇에서는 물체 영역 분리, 작업 공간 segmentation, 장애물 mask 생성, graspable region 추정 등에 연결될 수 있다.</p>
<ul>
<li><strong>왜 Skip Connection이 중요한가</strong></li>
</ul>
<p>Encoder는 이미지를 압축하면서 더 넓은 문맥과 의미 정보를 얻는다. 하지만 pooling이나 stride로 해상도가 줄어들면 작은 물체의 위치나 경계 정보가 사라질 수 있다. Decoder가 단독으로 해상도를 복원하면 의미는 알지만 경계가 흐릿한 mask가 나올 수 있다.</p>
<p>Skip connection은 encoder의 얕은 단계에서 보존된 위치 정보를 decoder로 직접 전달한다. 그래서 U-Net은 “무엇인지”를 판단하는 깊은 feature와 “어디에 있는지”를 알려주는 얕은 feature를 함께 사용한다.</p>
<p><strong>U-Net 실습 정리: 이해할 점</strong></p>
<p>U-Net을 단순히 segmentation 모델 이름으로 외우면 부족하다. 중요한 것은 segmentation이 classification과 다르게 픽셀 단위 위치 정보를 요구한다는 점이다. Downsampling으로 의미를 얻고, upsampling으로 위치를 복원하며, skip connection으로 경계를 살리는 구조를 이해해야 한다.</p>
<p>U-Net을 볼 때는 각 단계의 feature map 크기가 어떻게 변하는지 따라가면 구조가 이해된다. Encoder에서 해상도는 줄고 채널 수는 늘어난다. Decoder에서는 해상도가 다시 커지고, skip connection으로 encoder의 feature가 결합된다. 최종 layer는 각 픽셀에 대해 class score를 출력한다.</p>
<p><strong>U-Net 핵심 코드 인용</strong></p>
<p>Semantic segmentation 실습에서 U-Net을 볼 때는 encoder가 해상도를 줄이며 의미 정보를 만들고, decoder가 해상도를 되살리며 pixel 단위 출력을 만든다는 점을 코드 구조로 읽어야 한다.</p>
<pre><code class="language-python">inputs = Input(shape=(height, width, channels))

c1 = Conv2D(64, (3, 3), activation=&#39;relu&#39;, padding=&#39;same&#39;)(inputs)
p1 = MaxPooling2D((2, 2))(c1)

c2 = Conv2D(128, (3, 3), activation=&#39;relu&#39;, padding=&#39;same&#39;)(p1)
p2 = MaxPooling2D((2, 2))(c2)

u3 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding=&#39;same&#39;)(p2)
u3 = concatenate([u3, c1])
outputs = Conv2D(num_classes, (1, 1), activation=&#39;softmax&#39;)(u3)</code></pre>
<p><code>MaxPooling2D</code>는 feature map의 해상도를 줄이고 receptive field를 키운다. 이 과정에서 위치 정보가 일부 손실되므로, decoder에서 <code>Conv2DTranspose</code>로 해상도를 키울 때 encoder feature를 <code>concatenate</code>로 다시 붙인다. 이것이 skip connection이다.</p>
<p>마지막 <code>Conv2D(num_classes, (1, 1), activation=&#39;softmax&#39;)</code>는 각 pixel마다 class score를 만든다. Classification은 이미지 전체에 label 하나를 붙이지만, semantic segmentation은 모든 pixel에 label을 붙인다. 로봇에서는 이 mask가 작업 영역, 장애물 영역, 잡을 물체 영역을 나누는 데 쓰이고, depth와 결합하면 mask 내부의 3D point 후보를 만들 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>U-Net은 encoder-decoder와 skip connection으로 의미 정보와 위치 정보를 함께 보존하는 segmentation 모델이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Robotics] 4. 고전 CV & Image Processing 이론 정리]]></title>
            <link>https://velog.io/@jack_7711/Robotics-%EA%B3%A0%EC%A0%84-CV-Image-Processing-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Robotics-%EA%B3%A0%EC%A0%84-CV-Image-Processing-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 22 Jun 2026 05:10:22 GMT</pubDate>
            <description><![CDATA[<h1 id="0-전체-내용-요약과-키워드">0. 전체 내용 요약과 키워드</h1>
<p>이 문서는 딥러닝 이전의 컴퓨터비전 기초를 이미지의 수치적 표현과 규칙 기반 처리 관점에서 정리한다. 이미지는 픽셀 배열이며, grayscale/RGB, histogram, contrast, noise, edge, region 같은 신호 특성을 이해해야 이후 detection과 segmentation 결과도 해석할 수 있다.</p>
<p>전처리, filtering, convolution, edge detection, thresholding, segmentation, morphology는 영상에서 의미 있는 구조를 드러내기 위한 단계다. Feature matching과 homography는 서로 다른 이미지 사이의 대응 관계와 기하 변환을 다루며, PCA/eigen image는 고차원 이미지 데이터를 낮은 차원 특징으로 해석하는 흐름을 보여 준다. 로봇에서는 이 개념들이 작업 영역 분리, 물체 후보 추출, 위치 추정, 시각 디버깅의 기반이 된다.</p>
<p><strong>키워드</strong>: image representation, pixel, grayscale, RGB, histogram, histogram equalization, CLAHE, masking, ROI, filtering, convolution, blur, sharpening, edge detection, thresholding, segmentation, morphology, erosion, dilation, feature extraction, keypoint, descriptor, matching, homography, PCA, eigen image</p>
<h1 id="1-이미지-표현과-전처리">1. 이미지 표현과 전처리</h1>
<h2 id="11-이미지-표현과-기본-전처리">1.1. 이미지 표현과 기본 전처리</h2>
<h3 id="111-학습-목적">1.1.1. 학습 목적</h3>
<p>컴퓨터비전에서 이미지는 픽셀 값의 배열이다. 사람은 이미지를 장면으로 보지만, 알고리즘은 픽셀 값, 채널, 밝기 분포, 경계, 질감, 노이즈를 본다. 따라서 CV의 출발점은 이미지를 어떻게 수치 데이터로 이해하고, 이후 알고리즘이 보기 좋은 형태로 바꾸는지 익히는 것이다.</p>
<p>전처리는 단순히 이미지를 예쁘게 만드는 과정이 아니다. Thresholding, segmentation, feature extraction, CNN, detection이 잘 작동하도록 입력 신호를 정리하는 과정이다. 조명, 대비, 노이즈, 크기, 색상 분포가 달라지면 같은 알고리즘도 전혀 다른 결과를 낼 수 있다.</p>
<h3 id="112-grayscale-rgb-histogram">1.1.2. Grayscale, RGB, Histogram</h3>
<p>Grayscale 이미지는 각 픽셀이 하나의 밝기 값을 가진다. RGB 이미지는 red, green, blue 세 채널을 가진다. 알고리즘에 따라 grayscale로 변환해 밝기 구조만 보기도 하고, RGB나 HSV 같은 색 공간에서 색 정보를 활용하기도 한다.</p>
<p>Histogram은 이미지의 픽셀 값 분포를 보여 준다. 어두운 이미지는 낮은 픽셀 값에 몰려 있고, 대비가 낮은 이미지는 좁은 범위에 값이 집중된다. Histogram을 보면 thresholding이 쉬울지, contrast enhancement가 필요한지 판단할 수 있다.</p>
<h3 id="113-histogram-equalization과-clahe">1.1.3. Histogram Equalization과 CLAHE</h3>
<p>Histogram equalization은 픽셀 값 분포를 넓혀 대비를 높이는 방법이다. 어두운 영역과 밝은 영역의 차이를 키워 segmentation이나 edge detection이 더 잘 보이도록 만들 수 있다. 하지만 전체 이미지에 동일하게 적용하면 특정 영역에서 과도한 대비 증가나 노이즈 강조가 생길 수 있다.</p>
<p>CLAHE는 Contrast Limited Adaptive Histogram Equalization이다. 이미지를 작은 영역으로 나누고, 각 영역에서 대비를 향상시키되 clip limit을 둬 과도한 증폭을 줄인다. 의료 영상이나 조명 차가 큰 이미지에서 유용하다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/d789aeba-a675-4f98-b303-13fb69ffa506/image.png" alt=""></p>
<p>이 결과 이미지는 histogram equalization을 통해 전체 대비가 바뀐 모습을 보여 준다. 핵심은 밝기 값을 재분배해 어두운 영역의 구조를 더 잘 드러내는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/9387cd85-8f18-4cdc-8a62-c5e71e6c75d3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/3062861c-2fb6-43ec-8891-8ad6ae4683db/image.png" alt=""></p>
<p>CLAHE 비율별 결과 이미지는 clip limit이나 보정 강도가 달라질 때 영상의 대비와 노이즈가 어떻게 바뀌는지 보여 준다. 비율이 낮으면 변화가 약하고, 강하게 적용하면 구조는 더 도드라지지만 노이즈나 인위적 대비가 커질 수 있다.</p>
<h3 id="114-masking과-roi">1.1.4. Masking과 ROI</h3>
<p>Mask는 이미지에서 관심 영역만 남기고 나머지를 제외하는 방법이다. 객체가 있는 영역만 처리하거나, 특정 색상/밝기 범위만 선택할 때 사용한다. ROI는 Region of Interest로, 전체 이미지가 아니라 필요한 부분만 잘라 처리하는 방식이다.</p>
<p>실습 이미지에는 mask와 PCB crop/translation/defect 이미지가 포함되어 있다. 이는 전체 이미지에서 관심 영역을 추출하고, 위치 변화나 결함을 비교하는 흐름을 보여 준다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/c98b82b7-56bf-4a6f-86c9-69d840117857/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/579f5ad5-5af0-4d6e-b978-dd212063be58/image.png" alt=""></p>
<p>PCB 예제는 이미지 정렬, 결함 비교, 관심 영역 추출이 전처리와 연결된다는 점을 보여 준다. 같은 대상이라도 위치가 조금 바뀌면 픽셀 단위 비교가 어려워지므로 crop, translation, alignment 같은 처리가 필요하다.</p>
<h3 id="115-이미지-전처리-실습-정리">1.1.5. 이미지 전처리 실습 정리</h3>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>전처리는 이후 단계의 성능을 결정한다. Contrast가 낮으면 thresholding이 어려워지고, noise가 많으면 edge와 작은 객체가 잘못 검출된다. 반대로 전처리를 과하게 적용하면 원래 구조가 왜곡될 수 있다.</p>
<p>따라서 전처리는 “무조건 좋은 이미지”를 만드는 것이 아니라, 뒤에서 어떤 알고리즘을 사용할지에 맞게 필요한 신호를 살리고 불필요한 변화를 줄이는 과정이다.</p>
<ul>
<li><strong>기본 이미지 처리 노트북의 범위</strong></li>
</ul>
<p><code>ROS/CV/CV_exercise#2/basic_image_processing.ipynb</code>는 image loading, grayscale 변환, histogram, histogram equalization, CLAHE, masking, crop, translation, video/background subtraction 같은 기초 전처리를 다룬다. 함께 있는 <code>Histogram_Equalization_eqImg.png</code>, <code>CLHE_ratio0.01.png</code>부터 <code>CLHE_ratio1.0.png</code>까지의 결과 이미지는 contrast enhancement 강도에 따라 영상이 어떻게 달라지는지 비교하기 위한 산출물이다.</p>
<ul>
<li><strong>Histogram equalization을 왜 쓰는가</strong></li>
</ul>
<p>Histogram equalization은 어두운 영역이나 좁은 밝기 범위에 몰린 픽셀 값을 더 넓은 범위로 펴서 contrast를 키운다. 하지만 모든 영상에 무조건 좋은 것은 아니다. CLAHE처럼 local region별로 equalization을 적용하면 지역 contrast를 살릴 수 있지만, clip limit이나 ratio가 과하면 noise까지 강조된다. 그래서 실습에서 여러 CLAHE ratio 결과를 저장해 비교하는 것이다.</p>
<ul>
<li><strong>Mask, crop, translation이 필요한 이유</strong></li>
</ul>
<p><code>pcb.png</code>, <code>pcbCropped.png</code>, <code>pcbCroppedTranslated.png</code>, <code>pcbCroppedTranslatedDefected.png</code> 같은 자료는 전처리가 단순 미화가 아니라 비교와 검출의 기준을 맞추는 작업임을 보여 준다. ROI crop은 관심 영역만 남겨 계산량과 잡음을 줄이고, translation은 template이나 기준 이미지와 위치를 맞추는 데 쓰인다. 결함 검출에서는 정렬이 조금만 틀어져도 차영상이나 matching 결과가 결함처럼 보일 수 있다.</p>
<ul>
<li><strong>Video와 background subtraction</strong></li>
</ul>
<p><code>Background_Subtraction.avi</code>, <code>surveillance.avi</code>는 영상에서 시간 방향 정보를 활용하는 예다. 정지 이미지 전처리가 한 frame의 픽셀 분포를 다룬다면, background subtraction은 여러 frame에서 배경 모델을 만들고 움직이는 foreground를 분리한다. 로봇에서는 conveyor 위 움직이는 물체, 작업자 접근, 동적 장애물 검출로 이어질 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>이미지 전처리는 픽셀 분포, 대비, 노이즈, 관심 영역을 조정해 이후 CV 알고리즘이 의미 있는 신호를 볼 수 있게 만드는 과정이다.</p>
<h2 id="12-filtering과-edge-detection">1.2. Filtering과 Edge Detection</h2>
<h3 id="121-filtering과-convolution">1.2.1. Filtering과 Convolution</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>Convolution은 이미지 처리와 CNN의 공통 기반이 되는 연산이다. 작은 kernel을 이미지 위로 이동시키며 주변 픽셀과 가중합을 계산한다. Kernel 값에 따라 smoothing, sharpening, edge detection, feature extraction 같은 다양한 효과를 만들 수 있다.</p>
<ul>
<li><strong>왜 주변 픽셀을 함께 보는가</strong></li>
</ul>
<p>이미지의 의미는 픽셀 하나에만 있지 않다. 경계, 질감, 선, 모서리, 노이즈는 주변 픽셀과의 관계에서 나타난다. Convolution은 한 픽셀 주변의 작은 영역을 함께 보고, 그 지역 패턴이 어떤 성격을 가지는지 계산한다.</p>
<p>이 때문에 convolution은 지역적 특징을 다루는 데 적합하다. 고전 영상처리에서는 사람이 kernel 값을 정해 특정 패턴을 강조했고, CNN에서는 데이터가 그 kernel 값을 학습한다.</p>
<ul>
<li><strong>Filtering</strong></li>
</ul>
<p>Smoothing kernel은 주변 픽셀을 평균내어 노이즈를 줄인다. Sharpening kernel은 중심 픽셀과 주변 픽셀의 차이를 강조해 경계를 더 뚜렷하게 만든다. Sobel 같은 edge detection kernel은 x 방향이나 y 방향의 밝기 변화량을 계산한다.</p>
<p>즉 convolution은 이미지에서 지역적인 패턴을 계산하는 일반적인 틀이다.</p>
<ul>
<li><strong>Padding과 Stride</strong></li>
</ul>
<p>Convolution 결과의 크기는 padding과 stride에 따라 달라진다. Padding은 이미지 가장자리에 값을 덧붙여 출력 크기를 유지하거나 경계 정보를 덜 잃게 하는 방법이다. Stride는 kernel을 몇 칸씩 이동할지 정한다. Stride가 커지면 출력 feature map 크기가 줄고 계산량도 줄지만, 세밀한 위치 정보가 손실될 수 있다.</p>
<p>이 개념은 CNN에서도 그대로 이어진다. Classification에서는 어느 정도 위치 정보 손실을 허용할 수 있지만, segmentation에서는 위치 정보가 중요하므로 stride와 pooling으로 줄어든 해상도를 다시 복원해야 한다.</p>
<ul>
<li><strong>CNN과의 연결</strong></li>
</ul>
<p>Convolution을 이해하면 CNN도 더 잘 이해된다. 전통적 영상처리에서는 사람이 kernel을 설계했다. CNN에서는 kernel의 weight를 데이터로부터 학습한다. CNN의 convolution layer는 수작업 필터를 넘어, classification이나 detection에 필요한 특징 추출 필터를 자동으로 학습하는 구조다.</p>
<ul>
<li><strong>Kernel이 결과를 바꾸는 방식</strong></li>
</ul>
<p>Kernel은 어떤 주변 픽셀을 얼마나 반영할지 결정한다. 평균 필터는 주변 값을 고르게 반영해 노이즈를 줄이지만 edge도 흐리게 만든다. Gaussian filter는 중심에 가까운 픽셀에 더 큰 가중치를 주어 더 자연스러운 smoothing을 만든다. Sharpening kernel은 중심과 주변의 차이를 강조해 경계를 강하게 만든다.</p>
<p>Edge detection kernel은 방향성을 가진다. x 방향 gradient를 보는 kernel과 y 방향 gradient를 보는 kernel은 서로 다른 edge를 강조한다. 따라서 convolution 결과는 kernel의 수치뿐 아니라 kernel이 어떤 방향과 구조를 가정하는지에 따라 달라진다.</p>
<p><strong>Filtering 실습 정리: 해석 기준</strong></p>
<p>Filtering 실습에서는 결과 이미지만 보는 것이 아니라, 어떤 kernel이 어떤 영상 구조를 강조했는지 설명해야 한다. 노이즈 제거가 잘 되었더라도 중요한 경계가 사라졌다면 좋은 전처리라고 보기 어렵다. 반대로 edge를 강하게 만들었더라도 noise까지 같이 강조되면 후속 segmentation이 불안정해질 수 있다.</p>
<p><strong>Filtering 실습 정리: 확인한 점</strong></p>
<p>Kernel size와 결과의 관계가 중요하다. Kernel이 커질수록 더 넓은 영역을 한 번에 보지만, 세밀한 정보가 흐려질 수 있다. Kernel이 작으면 세부 구조는 보존되지만 노이즈 제거 효과가 약할 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Convolution은 이미지의 지역 패턴을 계산하는 기본 연산이며, 고전 영상처리와 CNN을 연결한다.</p>
<h3 id="122-edge-detection">1.2.2. Edge Detection</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>Edge는 이미지에서 밝기나 색상이 급격하게 변하는 위치다. 객체의 경계, 그림자, 질감 변화, 선 구조가 edge로 나타날 수 있다. Edge detection은 segmentation, feature extraction, object recognition의 기본 단계로 사용된다.</p>
<ul>
<li><strong>왜 밝기 변화가 경계 단서가 되는가</strong></li>
</ul>
<p>객체와 배경은 서로 다른 표면, 색상, 조명 반응을 가지는 경우가 많다. 그래서 객체의 경계에서는 픽셀 값이 급격히 변한다. Edge detection은 이 변화량을 계산해 “여기서 무언가가 달라진다”는 위치를 찾는다.</p>
<p>하지만 모든 edge가 객체 경계는 아니다. 그림자, 질감, 글자, 반사도 edge를 만든다. 따라서 edge는 경계 후보이지 정답 경계가 아니다. 이 차이를 이해해야 edge 결과를 segmentation이나 feature extraction에 올바르게 사용할 수 있다.</p>
<ul>
<li><strong>대표 방법</strong></li>
</ul>
<p>Sobel filter는 x 방향과 y 방향의 gradient를 계산해 edge를 찾는다. Laplacian filter는 2차 미분을 사용해 변화가 급격한 지점을 강조한다. Canny edge detector는 smoothing, gradient 계산, non-maximum suppression, hysteresis thresholding을 결합해 더 안정적인 edge를 찾는다.</p>
<p>Sobel은 방향별 변화량을 보기 때문에 수평/수직 경계의 강도를 해석하기 좋다. Laplacian은 변화가 급격한 지점을 더 직접적으로 강조하지만 noise에도 민감하다. Canny는 여러 단계를 결합해 얇고 연결성 있는 edge를 얻으려는 방법이다.</p>
<ul>
<li><strong>주의할 점</strong></li>
</ul>
<p>Edge가 항상 객체 경계와 일치하지는 않는다. 조명 변화나 질감도 edge를 만들 수 있고, 흐릿한 경계는 edge로 잘 잡히지 않을 수 있다. 따라서 edge detection 결과는 후처리나 다른 정보와 함께 해석해야 한다.</p>
<ul>
<li><strong>Morphology와의 결합</strong></li>
</ul>
<p>Edge detection 결과는 얇고 끊어진 선으로 나타나는 경우가 많다. Dilation을 적용하면 끊어진 edge를 연결하거나 더 두껍게 만들 수 있고, erosion을 적용하면 불필요하게 두꺼운 영역을 줄일 수 있다. Closing을 사용하면 경계 사이의 작은 틈을 메울 수 있다.</p>
<p>실습 이미지에서 <code>Edge_Detection_erodedEdge</code>, <code>Edge_Detection_dilatedEdge</code>, <code>Edge_Detection_combinedEdge</code> 같은 결과가 있는 것은 edge detection이 단독으로 끝나는 것이 아니라 morphology 후처리와 함께 쓰인다는 점을 보여 준다.</p>
<ul>
<li><strong>Segmentation과의 연결</strong></li>
</ul>
<p>Edge는 segmentation의 단서가 될 수 있다. 경계가 분명한 객체는 edge를 이용해 영역을 나누기 쉽다. 하지만 texture가 많은 이미지에서는 객체 내부에도 edge가 많아져 segmentation이 어려워질 수 있다. 따라서 edge detection은 thresholding, region labeling, morphology와 함께 해석해야 한다.</p>
<p><strong>Edge Detection 실습 정리</strong></p>
<p>Morphology와 edge detection은 서로 연결된다. Dilation이나 erosion을 통해 edge를 두껍게 하거나 얇게 만들 수 있고, thresholding 결과의 경계를 morphology로 정리할 수도 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Edge detection은 이미지의 급격한 변화 지점을 찾아 객체 경계와 구조를 해석하는 과정이다.</p>
<h2 id="13-segmentation과-morphology">1.3. Segmentation과 Morphology</h2>
<h3 id="131-segmentation">1.3.1. Segmentation</h3>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>Segmentation은 이미지를 의미 있는 영역으로 나누는 작업이다. 컴퓨터비전에서 단순히 이미지 전체가 어떤 클래스인지 맞히는 것만으로는 충분하지 않을 때가 많다. 객체가 이미지 안에서 어디에 있는지, 어떤 픽셀들이 같은 영역에 속하는지 알아야 이후 counting, measurement, detection, tracking, robot grasping으로 연결할 수 있다.</p>
<p>수업 실습에서는 thresholding, adaptive thresholding, Otsu, hole filling, region labeling 같은 고전 segmentation 흐름을 다뤘다. 이 흐름은 최신 딥러닝 segmentation을 이해하기 전에도 중요한 기본기다. 픽셀 분포, 조명, 후처리 조건이 결과에 어떤 영향을 주는지 직접 볼 수 있기 때문이다.</p>
<ul>
<li><strong>Thresholding</strong></li>
</ul>
<p>Thresholding은 픽셀 값을 기준으로 전경과 배경을 나누는 가장 기본적인 segmentation 방법이다. Global thresholding은 이미지 전체에 하나의 기준값을 적용한다. 이미지 조명이 균일하고 전경/배경 밝기 차이가 크면 효과적이다.</p>
<p>하지만 실제 이미지는 조명이 균일하지 않다. 신문 이미지처럼 글자, 사진, 배경이 섞여 있거나, 조명이 한쪽으로 치우친 경우 하나의 threshold로는 모든 영역을 잘 나누기 어렵다. 이때 adaptive thresholding은 지역 영역별로 threshold를 계산해 조명 변화에 더 유연하게 대응한다.</p>
<p>Otsu thresholding은 전경과 배경의 분산 차이를 이용해 threshold를 자동으로 찾는 방법이다. 사람이 기준값을 직접 고르지 않아도 되지만, 이미지가 두 클래스 정도로 잘 나뉜다는 가정이 어느 정도 필요하다.</p>
<ul>
<li><strong>Hole Filling과 Region Labeling</strong></li>
</ul>
<p>Thresholding으로 전경/배경을 나누면 객체 내부에 구멍이 생기거나 작은 잡음 영역이 남을 수 있다. Hole filling은 객체 내부의 빈 영역을 채워 하나의 온전한 영역으로 만든다. Region labeling은 연결된 픽셀 덩어리를 서로 다른 객체 후보로 나누는 과정이다.</p>
<p>Region labeling은 segmentation 결과를 “픽셀의 집합”에서 “객체 단위 후보”로 바꾼다. 이 단계가 있어야 객체 개수 세기, 크기 측정, 위치 추정 같은 후속 작업을 할 수 있다.</p>
<ul>
<li><strong>로봇/CV 연결</strong></li>
</ul>
<p>로봇 perception에서 segmentation은 물체 영역이나 장애물 영역을 구분하는 데 쓰일 수 있다. Bounding box보다 mask가 필요한 상황, 예를 들어 grasp 가능한 영역을 찾거나 작업 공간에서 물체의 실제 윤곽을 알아야 하는 경우 segmentation이 중요하다.</p>
<p><strong>Segmentation 실습 정리</strong></p>
<p><strong>실습 이미지 확인 실습 정리</strong></p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/9449f2ef-c051-4468-894d-1585ef963590/image.png" alt=""></p>
<p>이 이미지는 신문 이미지가 흑백 영역으로 분리된 결과다. 큰 제목과 사진 영역은 비교적 분명하게 분리되지만, 사진 내부의 밝기 변화와 글자 주변에서는 세부 정보가 거칠게 나뉜다. 이를 통해 global thresholding은 단순하고 빠르지만, 이미지 내부의 지역적 조명과 질감 변화까지 섬세하게 처리하지는 못한다는 점을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/08124d79-bc1a-4626-b9a9-858f8bf03f18/image.png" alt=""></p>
<p>지역 적응 thresholding 결과는 이미지의 작은 영역마다 기준을 다르게 적용한다. 조명이 균일하지 않은 상황에서는 global threshold보다 나은 결과를 만들 수 있지만, window 크기나 지역 통계 설정에 따라 잡음이 늘거나 경계가 불안정해질 수 있다.</p>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>Segmentation은 한 번의 함수 호출로 끝나지 않는다. 입력 이미지의 밝기 분포를 보고, thresholding 방식을 선택하고, morphology나 hole filling으로 후처리하고, region labeling으로 객체 단위 정보를 만든다. 이 전체 흐름을 이해해야 segmentation 결과를 해석할 수 있다.</p>
<p>특히 결과가 좋다/나쁘다로 끝내면 안 된다. 어떤 조명 조건에서 global thresholding이 실패했는지, adaptive thresholding이 어떤 부분을 보완했는지, hole filling과 labeling이 어떤 오류를 줄였는지를 설명해야 한다.</p>
<ul>
<li><strong>Thresholding 실습의 목적</strong></li>
</ul>
<p><code>ROS/CV/CV_exercise#3/week4_exercise.ipynb</code>와 결과 이미지들은 global thresholding, graylevel thresholding, locally adaptive thresholding, Otsu thresholding, hole filling, region labeling을 다룬다. <code>Global_Thresholding_bw.png</code>, <code>Locally_Adaptive_Thresholding_local.png</code>, <code>Graylevel_Thresholding_thresholded.png</code> 같은 산출물은 threshold 기준을 어떻게 잡느냐에 따라 foreground/background가 달라진다는 점을 보여 준다.</p>
<ul>
<li><strong>Global과 local threshold의 차이</strong></li>
</ul>
<p>Global threshold는 영상 전체에 하나의 기준값을 적용한다. 조명이 균일하고 객체와 배경의 밝기 차이가 분명하면 간단하고 빠르다. 하지만 <code>paper.png</code>, <code>book.png</code>, <code>news.png</code>처럼 조명이 위치마다 다르거나 그림자가 있는 경우에는 한 기준값으로 전체 영역을 잘 나누기 어렵다. Local/adaptive threshold는 주변 영역의 통계로 기준값을 정하므로 비균일 조명에서 더 안정적일 수 있다.</p>
<ul>
<li><strong>Otsu가 해결하려는 문제</strong></li>
</ul>
<p>Otsu thresholding은 threshold 값을 사람이 직접 정하지 않고, 두 class의 분산이 잘 분리되도록 기준값을 선택한다. <code>otsu_animation.avi</code>는 threshold가 바뀔 때 class 분리가 어떻게 달라지는지 이해하기 위한 자료다. Otsu가 잘 동작하려면 foreground와 background의 histogram이 어느 정도 분리되어 있어야 한다. 두 분포가 심하게 겹치면 자동 threshold도 안정적이지 않다.</p>
<ul>
<li><strong>Hole filling과 region labeling이 필요한 이유</strong></li>
</ul>
<p>Thresholding만으로 얻은 binary mask에는 구멍, 작은 잡음, 끊어진 영역이 남을 수 있다. <code>Hole_Filling_bw.png</code>, <code>Hole_Filling_filled.png</code>는 객체 내부 hole을 채우는 후처리의 의미를 보여 준다. <code>Region_Labeling_bw.png</code>, <code>Region_Labeling_rgbLabel.png</code>는 연결된 foreground 영역마다 label을 붙여 객체 개수와 위치를 다루는 단계다.</p>
<ul>
<li><strong>얼굴/객체 filtering 예시</strong></li>
</ul>
<p><code>Face_ref_*</code>, <code>Face_Training_*</code>, <code>Face_Test_*</code>, <code>Filtered_Face_*</code>, <code>Filtered_Face_Detection.png</code>는 segmentation 이후 조건 기반 filtering이 이어질 수 있음을 보여 준다. 단순히 foreground를 얻는 것에서 끝나지 않고, 크기, 모양, 위치, 색상, texture 조건으로 관심 객체만 남겨야 실제 detection pipeline이 된다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Segmentation은 픽셀을 의미 있는 영역으로 나누고, 후처리를 통해 객체 단위 정보로 바꾸는 컴퓨터비전의 핵심 과정이다.</p>
<p><strong>Morphology</strong></p>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>Morphology는 이미지의 형태를 기준으로 처리하는 방법이다. Thresholding이나 segmentation을 수행한 뒤에는 작은 잡음, 끊어진 선, 내부 구멍, 붙어버린 객체 같은 문제가 자주 생긴다. Morphology는 이런 문제를 구조 요소를 사용해 형태적으로 다듬는다.</p>
<p>대표 연산은 erosion, dilation, opening, closing이다. 이 연산들은 픽셀 값을 단순히 부드럽게 만드는 필터가 아니라, 객체의 크기와 연결성, 구멍, 경계를 조절한다.</p>
<ul>
<li><strong>Erosion과 Dilation</strong></li>
</ul>
<p>Erosion은 객체 영역을 깎아내는 연산이다. 작은 객체나 얇은 연결이 사라질 수 있다. 따라서 작은 잡음을 제거하거나 객체를 분리하는 데 쓰일 수 있다. 하지만 과하게 적용하면 실제 객체도 줄어든다.</p>
<p>Dilation은 객체 영역을 확장하는 연산이다. 끊어진 선을 연결하거나 작은 구멍을 메울 수 있다. 하지만 과하게 적용하면 가까운 객체들이 서로 붙어버릴 수 있다.</p>
<ul>
<li><strong>Opening과 Closing</strong></li>
</ul>
<p>Opening은 erosion 후 dilation을 수행한다. 작은 잡음을 먼저 제거하고, 남은 객체의 크기를 어느 정도 복원한다. Closing은 dilation 후 erosion을 수행한다. 작은 구멍이나 틈을 메운 뒤 객체 크기를 다시 조정한다.</p>
<p>중요한 것은 연산 순서다. Erosion과 dilation은 서로 반대처럼 보이지만, 순서에 따라 결과가 달라진다. Opening은 작은 전경 잡음을 제거하는 데 적합하고, closing은 객체 내부의 작은 배경 구멍을 메우는 데 적합하다.</p>
<ul>
<li><strong>구조 요소</strong></li>
</ul>
<p>Morphology의 핵심은 구조 요소다. 구조 요소의 크기와 모양에 따라 보존되는 형태와 제거되는 형태가 달라진다. 작은 원형 구조 요소는 작은 잡음 제거에 적합하고, 선형 구조 요소는 특정 방향의 선을 강조하거나 제거할 수 있다.</p>
<p>따라서 morphology는 “무슨 함수를 썼는가”보다 “어떤 구조 요소로 어떤 형태를 보존하려 했는가”가 중요하다.</p>
<ul>
<li><strong>로봇/CV 연결</strong></li>
</ul>
<p>로봇 perception에서는 segmentation mask를 바로 사용하기보다 morphology로 정리하는 경우가 많다. 작은 noise를 제거하고, 물체 영역의 구멍을 메우고, grasp 대상의 윤곽을 안정화하는 데 사용할 수 있다. Depth image의 빈 영역 보정이나 작업 공간 mask 정리에도 연결된다.</p>
<p><strong>Morphology 실습 정리</strong></p>
<p><strong>실습 이미지 확인 실습 정리</strong></p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/7e57b82b-94dc-436d-8195-5c3cb9da565f/image.png" alt=""></p>
<p>이 이미지는 동전 후보 영역이 서로 다른 색의 connected component로 표시된 결과다. 배경과 동전이 분리되고, 각 동전 영역이 개별 객체처럼 labeling된다. 일부 동전이 붙어 있거나 분리 경계가 애매한 부분도 보이는데, 이런 부분이 morphology와 region labeling에서 구조 요소 선택이 중요하다는 점을 보여 준다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/dd2f3473-0299-466d-bf8a-de335d357889/image.png" alt=""></p>
<p>Fence 예제에서는 erosion이 얇은 구조와 배경 잡음에 어떤 영향을 주는지 확인할 수 있다. 구조 요소를 어떻게 선택하느냐에 따라 울타리처럼 반복적인 선 구조가 보존되거나 사라진다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/c052b101-ef52-4c3f-a450-e750cfff39fd/image.png" alt=""></p>
<p>Closing 기반 작은 구멍 제거 결과는 객체 내부의 빈 영역을 메우는 morphology의 역할을 보여 준다. 단순 thresholding 결과에서는 내부 구멍이 남을 수 있지만, closing을 사용하면 더 온전한 객체 mask를 만들 수 있다.</p>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>Morphology는 segmentation 결과를 실제 객체 분석에 사용할 수 있도록 다듬는 과정이다. 결과가 좋아 보이는지보다, 어떤 형태가 제거되고 어떤 형태가 남았는지 설명하는 것이 중요하다. 구조 요소가 커지면 더 큰 잡음도 제거할 수 있지만 실제 객체 정보도 손상될 수 있다.</p>
<ul>
<li><strong>Erosion과 dilation 실습의 의미</strong></li>
</ul>
<p><code>ROS/CV/CV_exercise#4/code.ipynb</code>와 결과 이미지들은 1D erosion/dilation, binary erosion, dilation, graylevel morphology, edge detection, hole removal, noise removal, counting coins를 다룬다. <code>1D_Erosion_Dilation_*</code> 이미지는 structuring element 크기가 커질수록 신호의 작은 구조가 사라지거나 확장되는 과정을 보여 준다.</p>
<ul>
<li><strong>Structuring element가 결과를 결정한다</strong></li>
</ul>
<p><code>Binary_Erosion_Coins_disk_*</code>, <code>Binary_Erosion_Coins_square_*</code> 결과는 같은 erosion이라도 disk와 square 구조 요소가 다른 결과를 만든다는 점을 보여 준다. Morphology는 단순 필터가 아니라 “어떤 모양을 기준으로 객체를 해석할 것인가”를 정하는 연산이다. 원형 동전을 다룰 때 disk가 자연스럽고, 격자나 직선 구조를 다룰 때 square나 line 구조 요소가 더 적합할 수 있다.</p>
<ul>
<li><strong>Noise removal과 hole removal</strong></li>
</ul>
<p><code>Bacteria_noise*</code>, <code>Bacteria_denoise*</code>, <code>Small_Hole_Removal_*</code>는 morphology가 segmentation mask 후처리에 왜 필요한지 보여 준다. Erosion은 작은 흰 잡음을 줄일 수 있지만 객체도 함께 작아진다. Dilation은 끊어진 영역을 연결하거나 hole을 줄일 수 있지만 객체가 커진다. Opening과 closing은 이 두 효과를 순서대로 조합해 noise 제거와 구멍 보정을 수행한다.</p>
<ul>
<li><strong>Counting coins로 보는 객체 분석</strong></li>
</ul>
<p><code>Counting_Coins_bw*</code>, <code>Counting_Coins_dilated.png</code>, <code>Counting_Coins_label*</code>는 morphology와 region labeling이 연결되는 예다. 동전이 붙어 있거나 mask가 끊겨 있으면 label 개수가 실제 객체 개수와 달라진다. Morphology로 객체 영역을 정리한 뒤 labeling해야 count, centroid, area 같은 객체 속성을 안정적으로 얻을 수 있다.</p>
<ul>
<li><strong>Edge detection과 morphology의 연결</strong></li>
</ul>
<p><code>Edge_Detection_erodedEdge.png</code>, <code>Edge_Detection_dilatedEdge.png</code>, <code>Edge_Detection_combinedEdge.png</code>는 erosion/dilation 차이를 이용해 경계 성분을 만들 수 있음을 보여 준다. Edge는 gradient 연산으로만 얻는 것이 아니라 형태학적 연산으로도 추출할 수 있다. 이 관점은 binary mask의 외곽선이나 객체 경계 후처리에 유용하다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Morphology는 객체의 형태와 연결성을 기준으로 segmentation 결과를 다듬는 전처리/후처리 도구다.</p>
<h2 id="14-전처리-핵심-코드">1.4. 전처리 핵심 코드</h2>
<h3 id="141-전처리-threshold-morphology-핵심-코드-인용">1.4.1. 전처리, Threshold, Morphology 핵심 코드 인용</h3>
<p>Image preprocessing 실습은 한 장의 이미지를 바로 모델에 넣기 전에 contrast, noise, threshold, morphology를 조절하는 과정이다.</p>
<pre><code class="language-python">gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
eq = cv2.equalizeHist(gray)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
local_eq = clahe.apply(gray)</code></pre>
<p><code>equalizeHist</code>는 전체 histogram을 펴서 contrast를 키운다. 하지만 조명이 위치마다 다른 이미지에서는 전체 equalization이 일부 영역을 과하게 만들 수 있다. <code>CLAHE</code>는 작은 tile 단위로 contrast를 조절하고 clip limit으로 과증폭을 막는다. 그래서 조명 불균일이 있는 로봇 카메라 이미지에서는 global 방식과 local 방식을 비교해야 한다.</p>
<p>Threshold 실습의 핵심은 grayscale을 binary mask로 바꾸는 기준을 어디서 정하느냐다.</p>
<pre><code class="language-python">_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
adaptive = cv2.adaptiveThreshold(
    gray,
    255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
    cv2.THRESH_BINARY,
    11,
    2
)</code></pre>
<p><code>threshold</code>는 하나의 기준값으로 전체 이미지를 나눈다. <code>adaptiveThreshold</code>는 주변 영역의 밝기를 기준으로 pixel마다 다른 threshold를 적용한다. 그래서 배경 밝기가 균일하면 global threshold가 단순하고, 그림자나 조명 변화가 크면 adaptive threshold가 더 안정적일 수 있다.</p>
<p>Morphology는 binary mask의 모양을 다듬는 후처리다.</p>
<pre><code class="language-python">kernel = np.ones((3, 3), np.uint8)
eroded = cv2.erode(binary, kernel, iterations=1)
dilated = cv2.dilate(binary, kernel, iterations=1)
opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)</code></pre>
<p><code>erode</code>는 작은 흰 영역을 줄이고, <code>dilate</code>는 흰 영역을 키운다. <code>open</code>은 작은 noise를 제거하는 데, <code>close</code>는 객체 내부의 작은 구멍을 메우는 데 자주 쓴다. Segmentation mask나 YOLO 후처리에서 mask가 끊기거나 작은 noise가 생기면 morphology가 객체 count, contour, centroid 계산을 안정화한다.</p>
<h1 id="2-feature-extraction과-matching">2. Feature Extraction과 Matching</h1>
<h2 id="21-feature-matching">2.1. Feature Matching</h2>
<h3 id="211-학습-목적">2.1.1. 학습 목적</h3>
<p>Feature extraction은 이미지에서 반복적으로 찾을 수 있는 특징을 추출하는 과정이고, feature matching은 서로 다른 이미지에서 같은 장면이나 같은 물체에 해당하는 특징을 연결하는 과정이다. 이 개념은 template matching, image stitching, homography estimation, object recognition, tracking의 기반이 된다.</p>
<p>딥러닝 이전의 CV에서 feature는 사람이 설계한 기준으로 추출되었다. 하지만 이 사고방식은 여전히 중요하다. 로봇이 카메라로 본 장면과 이전 장면을 비교하거나, 서로 다른 시점의 이미지를 맞추거나, 평면 물체의 위치 관계를 추정할 때 feature matching이 필요하다.</p>
<h3 id="212-template-matching">2.1.2. Template Matching</h3>
<p>Template matching은 찾고 싶은 작은 이미지 조각을 큰 이미지 위에서 이동시키며 유사도를 계산하는 방식이다. 단순하고 직관적이지만 scale, rotation, illumination 변화에 약하다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/ee6c87bd-08d7-40ec-a375-1b84f784bd30/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/b27cccd9-9cb0-4aad-8115-c79f654ee03d/image.png" alt=""></p>
<p>교회 이미지와 창문 template은 template matching의 기본 구조를 보여 준다. 큰 이미지 안에서 작은 창문 패턴과 비슷한 위치를 찾는 것이다. 이 방식은 대상의 크기와 방향이 거의 일정할 때 유효하지만, 시점이나 scale이 변하면 성능이 떨어질 수 있다.</p>
<h3 id="213-keypoint와-descriptor">2.1.3. Keypoint와 Descriptor</h3>
<p>Harris corner, SIFT, ORB 같은 방법은 이미지에서 반복적으로 찾기 쉬운 keypoint를 찾고, 그 주변 패턴을 descriptor로 표현한다. Keypoint는 특징점의 위치이고, descriptor는 그 위치 주변의 모양을 수치 벡터로 나타낸 것이다.</p>
<p>SIFT는 scale과 rotation 변화에 강한 특징을 만드는 대표적인 방법이다. ORB는 빠른 계산을 목표로 하는 binary descriptor 계열 방법이다. 실습에서는 SIFT/ORB를 통해 서로 다른 이미지 사이의 대응점을 찾는 흐름을 확인한다.</p>
<h3 id="214-matching과-outlier-제거">2.1.4. Matching과 Outlier 제거</h3>
<p>Descriptor를 비교하면 서로 다른 이미지 사이의 대응점을 찾을 수 있다. 하지만 모든 match가 맞는 것은 아니다. 반복 패턴, 노이즈, 질감 부족, 조명 변화 때문에 잘못된 match가 생긴다.</p>
<p>RANSAC은 outlier가 섞인 match 중에서 일관된 변환 관계를 설명하는 subset을 찾는다. 이를 통해 homography 같은 기하 변환을 안정적으로 추정할 수 있다.</p>
<h3 id="215-homography">2.1.5. Homography</h3>
<p>Homography는 평면 장면이나 카메라 시점 변화 사이의 projective transform을 나타낸다. 책 표지, 건물 벽면, 평면 포스터처럼 하나의 평면에 가까운 대상은 homography로 시점 변화를 설명할 수 있다.</p>
<p>실습 이미지에는 book, church, coke, gates 같은 이미지 쌍이 포함되어 있다. 이들은 서로 다른 시점의 장면에서 feature를 찾고, matching과 homography를 통해 대응 관계를 추정하는 흐름과 연결된다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/37b3a97c-bbc3-4076-938b-c0bda7986500/image.jpg" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/499aff09-f6bc-40c7-8e44-b53d0b6b8de8/image.jpg" alt=""></p>
<h3 id="216-로봇cv-연결">2.1.6. 로봇/CV 연결</h3>
<p>로봇 perception에서 feature matching은 카메라 위치 추정, 물체 pose 추정, 시점 변화 보정, visual odometry의 기초와 연결된다. 로봇이 같은 물체를 다른 각도에서 봐도 같은 대상으로 인식하려면 feature와 기하 관계를 이해해야 한다.</p>
<h3 id="217-feature-matching-실습-정리">2.1.7. Feature Matching 실습 정리</h3>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>Feature matching은 이미지 전체를 비교하는 것이 아니다. 반복 가능한 지점을 찾고, 그 지점 주변을 descriptor로 표현하고, 대응점 사이의 기하 관계를 추정한다. 이 과정을 통해 이미지가 이동하거나 회전하거나 시점이 달라져도 같은 장면을 연결할 수 있다.</p>
<ul>
<li><strong>Template matching의 위치</strong></li>
</ul>
<p><code>ROS/CV/CV_exercise#5/CV_exercise#5_template_matching/code.ipynb</code>는 <code>church.png</code>와 <code>window.png</code>를 사용해 작은 template이 큰 이미지 안 어디에 있는지 찾는 흐름을 다룬다. Template matching은 sliding window로 template과 image patch의 유사도를 계산한다. 객체의 scale, rotation, perspective가 크게 변하지 않는 상황에서는 단순하고 직관적이다.</p>
<p>하지만 template matching은 대상의 크기나 회전이 바뀌면 약해진다. 그래서 feature descriptor 기반 matching을 함께 배운다. Template matching은 “정해진 모양이 거의 그대로 있는가”를 보는 방법이고, SIFT/ORB matching은 “시점과 크기가 달라도 대응되는 특징점이 있는가”를 보는 방법이다.</p>
<ul>
<li><strong>SIFT/ORB 실습의 흐름</strong></li>
</ul>
<p><code>ROS/CV/CV_exercise#6/code.ipynb</code>는 <code>gates.jpg</code>, <code>church1.jpg</code>, <code>church2.jpg</code>, <code>book1.jpg</code>, <code>book2.jpg</code>, <code>coke1.png</code>, <code>coke2.png</code> 같은 자료로 SIFT descriptor, keypoint visualization, descriptor matching을 수행한다. SIFT는 scale-space에서 특징점을 찾고 방향을 부여해 회전과 scale 변화에 비교적 강한 descriptor를 만든다. ORB는 더 빠른 binary descriptor를 사용해 실시간성에 유리하다.</p>
<ul>
<li><strong>Matching에서 좋은 대응점을 고르는 이유</strong></li>
</ul>
<p>Feature matching은 descriptor 거리만 작다고 끝나지 않는다. 잘못된 대응점이 섞이면 homography나 pose 추정이 틀어진다. 그래서 ratio test, cross-check, RANSAC 같은 후처리가 필요하다. 실습 이미지처럼 책 표지나 건물 facade를 맞출 때는 반복 pattern과 비슷한 texture가 많아 오매칭이 생기기 쉽다.</p>
<ul>
<li><strong>Video 자료와 tracking으로의 확장</strong></li>
</ul>
<p><code>Car-01.mp4</code>, <code>crew_4cif.mp4</code>, <code>ice_4cif.mp4</code>와 대응되는 <code>_KL.avi</code> 결과는 feature나 motion cue가 video tracking으로 확장될 수 있음을 보여 준다. 정지 이미지 matching은 두 이미지 사이 대응점 문제이고, video tracking은 시간에 따라 같은 대상의 위치를 계속 갱신하는 문제다. 로봇에서는 이 흐름이 visual servoing, object tracking, localization으로 이어질 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Feature matching은 이미지 사이의 반복 가능한 특징을 연결해 같은 장면의 대응 관계와 기하 변환을 추정하는 방법이다.</p>
<h3 id="218-feature-matching-핵심-코드-인용">2.1.8. Feature Matching 핵심 코드 인용</h3>
<p>Template matching 실습은 작은 template과 원본 이미지의 유사도를 위치별로 계산하는 과정이다.</p>
<pre><code class="language-python">church = imread(&#39;church.png&#39;).astype(np.float64)
window = imread(&#39;window.png&#39;).astype(np.float64)

church -= np.mean(church)
window -= np.mean(window)

flippedWindow = np.flipud(np.fliplr(window))
r = convolve2d(church, flippedWindow, mode=&#39;same&#39;)</code></pre>
<p>평균을 빼는 이유는 전체 밝기 차이가 matching score를 지배하지 않게 하기 위해서다. <code>flippedWindow</code>는 convolution 정의에 맞춘 template이고, <code>r</code>은 각 위치에서 template과 이미지 영역이 얼마나 비슷한지 나타내는 response map이다. 최고값 위치를 찾으면 template이 가장 잘 맞는 후보 위치를 얻는다.</p>
<p>SIFT 실습은 특징점 위치와 주변 패턴 표현을 분리해서 만든다.</p>
<pre><code class="language-python">sift = cv2.SIFT_create(contrastThreshold=0.04)
keypoints, descriptors = sift.detectAndCompute(img, None)
img_keypoints = cv2.drawKeypoints(
    img,
    selected_keypoints,
    None,
    flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
)</code></pre>
<p><code>keypoints</code>는 이미지의 어느 위치가 반복적으로 찾기 쉬운지를 담고, <code>descriptors</code>는 그 주변 모양을 비교 가능한 벡터로 바꾼다. 그래서 SIFT/ORB matching은 template matching처럼 같은 모양이 같은 크기와 방향으로 있는지만 보지 않고, scale과 rotation이 달라져도 대응되는 지역 특징이 있는지 비교할 수 있다.</p>
<h2 id="22-eigen-image와-pca">2.2. Eigen Image와 PCA</h2>
<h3 id="221-학습-목적">2.2.1. 학습 목적</h3>
<p>이미지는 픽셀 수만큼 차원이 큰 데이터다. 얼굴 이미지 하나가 92x112 픽셀이라면 10304차원 벡터로 볼 수 있다. 이런 고차원 데이터를 그대로 비교하면 계산도 어렵고, 어떤 변화가 중요한지 해석하기도 어렵다.</p>
<p>PCA는 데이터의 분산을 가장 잘 설명하는 축을 찾는 차원 축소 방법이다. Eigen image는 이미지 데이터에 PCA를 적용해 주요 변동 방향을 이미지처럼 표현한 것이다.</p>
<h3 id="222-왜-차원-축소가-필요한가">2.2.2. 왜 차원 축소가 필요한가</h3>
<p>고차원 픽셀 공간에서는 모든 픽셀이 같은 비중으로 비교된다. 하지만 실제 이미지 데이터에서 모든 픽셀이 같은 의미를 갖지는 않는다. 조명 변화, 얼굴 방향, 표정, 배경, 노이즈처럼 반복적으로 나타나는 변화가 있고, 이 변화 중 일부가 데이터 차이를 크게 설명한다.</p>
<p>PCA는 이런 주요 변동 방향을 찾아 원본 이미지보다 낮은 차원으로 표현한다. 이렇게 하면 계산량을 줄일 수 있고, 노이즈보다 데이터 전체를 설명하는 큰 패턴에 집중할 수 있다.</p>
<h3 id="223-이미지-데이터셋과-벡터-공간">2.2.3. 이미지 데이터셋과 벡터 공간</h3>
<p>실습 폴더에는 AT&amp;T face dataset 형태의 PGM 이미지들이 포함되어 있다. 각 얼굴 이미지는 같은 크기의 grayscale 이미지이며, 이를 펼치면 하나의 고차원 벡터가 된다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/266a54a8-dcb5-428e-95bc-7b1d2055809e/image.png" alt=""></p>
<pre><code>원본 얼굴 이미지
-&gt; 픽셀 행렬 A
-&gt; flatten된 10,304차원 벡터 x
-&gt; PCA 입력 행렬 X</code></pre><p>위 얼굴 이미지는 단순한 사진이 아니라 PCA 관점에서는 고차원 벡터 하나다. 여러 얼굴 벡터를 모으면 얼굴 데이터가 어떤 방향으로 많이 변하는지 계산할 수 있다.</p>
<h3 id="224-평균-이미지와-eigen-face">2.2.4. 평균 이미지와 Eigen Face</h3>
<p>Eigen face에서는 먼저 모든 얼굴의 평균 이미지를 계산한다. 각 얼굴 이미지는 평균 얼굴에서 얼마나 벗어나는지로 표현할 수 있다. PCA는 이 벗어남을 가장 잘 설명하는 주요 성분을 찾는다.</p>
<p>주요 성분은 얼굴 이미지의 변화 방향을 나타낸다. 예를 들어 조명 방향, 얼굴 형태, 눈/코/입 주변의 차이 같은 변동이 principal component로 나타날 수 있다.</p>
<h3 id="225-인식에서의-사용-방식">2.2.5. 인식에서의 사용 방식</h3>
<p>새 얼굴 이미지가 들어오면 같은 방식으로 평균 얼굴을 빼고 eigen face 축에 projection할 수 있다. 그러면 원본 픽셀 전체가 아니라 PCA 계수 벡터로 얼굴을 표현할 수 있다. 이 계수 벡터 사이의 거리를 비교하면 얼굴 유사도를 판단할 수 있다.</p>
<p>이 방식은 현대 딥러닝 embedding과 구조적으로 닮아 있다. 원본 이미지를 직접 비교하지 않고, 더 낮고 의미 있는 feature space에서 비교한다는 점이 같다.</p>
<h3 id="226-차원-축소의-의미">2.2.6. 차원 축소의 의미</h3>
<p>PCA를 사용하면 원래 픽셀 전체를 쓰지 않고도 얼굴을 낮은 차원의 계수로 표현할 수 있다. 이는 저장과 계산을 줄일 뿐 아니라, 데이터에서 중요한 변동과 덜 중요한 노이즈를 구분하는 데 도움을 준다.</p>
<p>현대 딥러닝에서도 embedding이라는 개념이 중요하다. 이미지를 직접 픽셀로 비교하는 대신, 의미 있는 feature space에서 비교하는 것이다. Eigen image와 PCA는 이런 사고방식의 고전적 출발점으로 볼 수 있다.</p>
<h3 id="227-eigen-image와-pca-실습-정리">2.2.7. Eigen Image와 PCA 실습 정리</h3>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>Eigen image 실습은 이미지를 단순 픽셀 배열이 아니라 벡터 공간의 점으로 보는 관점을 만든다. 얼굴 인식이나 이미지 비교에서 중요한 것은 픽셀 하나하나가 아니라, 데이터 전체의 주요 변동 구조를 찾는 것이다.</p>
<ul>
<li><strong>얼굴 이미지 dataset을 행렬로 바꾸는 이유</strong></li>
</ul>
<p><code>ROS/CV/CV_exercise#5/CV_exercise#5_eigen_image/code.ipynb</code>와 <code>att_faces_aligned_lighting</code> 자료는 여러 얼굴 이미지를 같은 크기와 정렬 상태로 맞춘 뒤 vector로 펼쳐 data matrix를 만드는 흐름을 다룬다. 각 이미지는 하나의 고차원 벡터가 되고, 여러 이미지가 모이면 얼굴 데이터가 차지하는 subspace를 PCA로 찾을 수 있다.</p>
<ul>
<li><strong>Mean face와 eigenface의 의미</strong></li>
</ul>
<p><code>Mean_Face.fig</code>, <code>Eigenfaces.fig</code>, <code>Fisherfaces.fig</code> 산출물은 평균 얼굴과 주요 변화 방향을 시각화한다. Mean face는 데이터 전체의 중심이고, eigenface는 얼굴 이미지들이 주로 어떻게 달라지는지를 나타내는 basis image다. 조명, 얼굴 윤곽, 눈/코/입 위치 차이가 주요 variance로 나타날 수 있다.</p>
<ul>
<li><strong>차원 축소가 인식에 도움이 되는 이유</strong></li>
</ul>
<p>원본 이미지 픽셀 전체를 그대로 비교하면 차원이 너무 높고 noise와 조명 변화의 영향을 크게 받는다. PCA는 가장 큰 분산 방향을 남겨 얼굴을 더 낮은 차원의 coefficient vector로 표현한다. 이 coefficient를 비교하면 원본 픽셀 비교보다 계산량이 줄고, 데이터의 주요 구조를 기준으로 인식할 수 있다.</p>
<ul>
<li><strong>Video keyframe 자료의 의미</strong></li>
</ul>
<p><code>keyframes</code>, <code>keyframes_cropped</code>, <code>light.mpg</code> 같은 자료는 eigen image가 정지 얼굴 사진뿐 아니라 frame sequence 분석으로 확장될 수 있음을 보여 준다. Video에서 frame을 추출하고 정렬/crop한 뒤 PCA를 적용하면 시간에 따라 변하는 조명이나 표정, 자세 변화가 어떤 주성분으로 나타나는지 볼 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Eigen image와 PCA는 고차원 이미지를 주요 변동 축으로 압축해 표현하고, 이미지 데이터를 feature space에서 이해하게 해 주는 방법이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Robotics] 3. Isaac Sim 이론 정리]]></title>
            <link>https://velog.io/@jack_7711/Robotics-Isaac-Sim-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Robotics-Isaac-Sim-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 22 Jun 2026 04:51:08 GMT</pubDate>
            <description><![CDATA[<h1 id="0-전체-내용-요약과-키워드">0. 전체 내용 요약과 키워드</h1>
<p>이 문서는 Isaac Sim을 로봇, 센서, 물리, 작업 시나리오를 가상 환경에서 검증하는 시뮬레이션 도구로 정리한다. Isaac Sim은 Omniverse와 USD 기반으로 로봇 모델, gripper, 물체, 물리 속성, camera/LiDAR/IMU/contact sensor를 하나의 scene 안에서 구성할 수 있다.</p>
<p>핵심 흐름은 digital twin, USD scene 구성, PhysX 물리, OmniGraph 데이터 흐름, Python scripting이다. Pick-and-place 실습에서는 URDF import, gripper assembly, articulation/controller 설정, 물체 pose, goal pose가 함께 맞아야 manipulation이 성립한다. Isaac Sim은 실제 로봇에 적용하기 전 perception, control, sensor pipeline을 검증하는 중간 실험장으로 이해할 수 있다.</p>
<p><strong>키워드</strong>: Isaac Sim, Omniverse, USD, OpenUSD, digital twin, PhysX, rigid body, collider, fixed joint, OmniGraph, sensor simulation, camera, LiDAR, IMU, contact sensor, URDF import, robot assembler, controller, pick-and-place, Python scripting, ROS2 bridge</p>
<h1 id="1-isaac-sim">1. Isaac Sim</h1>
<h2 id="11-isaac-sim-기본-구조">1.1. Isaac Sim 기본 구조</h2>
<h3 id="111-기본-개념">1.1.1. 기본 개념</h3>
<p>Isaac Sim은 NVIDIA Omniverse 기반의 로봇 시뮬레이션 환경이다. Gazebo가 ROS 생태계에서 많이 쓰이는 물리 시뮬레이터라면, Isaac Sim은 고품질 렌더링, 물리 시뮬레이션, 센서 시뮬레이션, synthetic data, 로봇 조작 실험에 강점을 가진다.</p>
<h3 id="112-센서-시뮬레이션">1.1.2. 센서 시뮬레이션</h3>
<p>Isaac Sim에서는 카메라 센서, LiDAR, IMU, contact sensor를 만들고, 물체를 배치하고, 로봇 모델을 import하고, controller를 통해 움직임을 실행할 수 있다. 이 과정은 실제 로봇 실험 전에 perception과 manipulation을 함께 검증하는 데 유용하다.</p>
<p>카메라 실습은 3D world와 2D image의 관계를 이해하게 한다. 카메라는 단순히 이미지를 저장하는 객체가 아니라, 3D 공간의 점을 이미지 평면 위 좌표로 투영하는 센서다.</p>
<h3 id="113-pick-and-place">1.1.3. Pick and Place</h3>
<p>Pick-and-place 실습은 로봇 모델 import, gripper assembly, 물체 생성, 목표 위치 설정, controller 실행이 모두 연결되어야 한다. 단순히 로봇 팔만 움직이는 것이 아니라, 그리퍼가 물체를 잡고, 목표 위치로 이동하고, 놓는 전체 작업 흐름을 구성한다.</p>
<p>이 실습은 manipulation이 perception, planning, control, physics가 모두 맞물리는 작업이라는 점을 보여 준다.</p>
<h3 id="114-코드-흐름에서-확인할-수-있는-구조">1.1.4. 코드 흐름에서 확인할 수 있는 구조</h3>
<p>Isaac Sim pick-and-place 코드에서는 먼저 SimulationApp을 실행하고, world를 만든 뒤 URDF importer로 로봇과 gripper 모델을 불러온다. 이후 robot assembler를 통해 로봇과 gripper를 결합하고, controller 설정 파일을 사용해 움직임을 제어한다.</p>
<p>이 흐름은 로봇 시뮬레이션이 단일 함수 호출이 아니라는 점을 보여 준다. 모델 import, articulation root, gripper frame, controller config, 물체 pose, goal pose가 모두 맞아야 pick-and-place 작업이 성립한다.</p>
<h3 id="115-로봇cv-연결">1.1.5. 로봇/CV 연결</h3>
<p>카메라 실습에서는 world point를 image coordinate로 변환하는 과정을 확인할 수 있다. 이는 CV 결과를 로봇 행동으로 연결할 때 핵심이다. 이미지에서 검출된 물체가 실제 3D 공간의 어디에 있는지 알아야 로봇이 접근할 수 있기 때문이다.</p>
<p>LiDAR, IMU, contact sensor 실습은 perception이 이미지에만 한정되지 않는다는 점을 보여 준다. 실제 로봇은 여러 센서를 결합해 자신의 상태와 주변 환경을 이해한다.</p>
<h3 id="116-로봇cv-연결">1.1.6. 로봇/CV 연결</h3>
<p>Isaac Sim은 CV와 로봇의 연결 지점에서도 중요하다. 시뮬레이션 카메라로 이미지를 얻고, 그 이미지에서 물체를 검출하고, 검출 결과를 로봇의 목표 위치로 변환해 pick-and-place를 수행하는 구조를 만들 수 있다.</p>
<h3 id="117-isaac-sim-실습-정리">1.1.7. Isaac Sim 실습 정리</h3>
<ul>
<li><strong>Isaac Sim은 시뮬레이터이면서 로봇 앱이다</strong></li>
</ul>
<p>실습 backup 자료에는 Isaac Sim 본체 소스 일부와 함께 <code>doosan-robot2/urdf/m0609_isaac_sim.urdf</code> 같은 로봇 import용 모델이 들어 있다. 여기서 중요한 것은 Isaac Sim이 단순 3D viewer가 아니라 USD scene, PhysX physics, sensor simulation, robot articulation, Python scripting을 함께 제공하는 robotics simulation application이라는 점이다.</p>
<ul>
<li><strong>URDF import와 USD scene</strong></li>
</ul>
<p>M0609 같은 실제 로봇을 Isaac Sim에서 쓰려면 URDF나 mesh를 가져와 USD scene 안의 articulation으로 구성해야 한다. URDF는 link/joint 구조를 제공하고, Isaac Sim은 이를 USD prim과 physics articulation으로 변환해 simulation에서 움직일 수 있게 한다. 변환 뒤에는 joint drive, collision, mass/inertia, material, scale, frame orientation을 확인해야 한다.</p>
<ul>
<li><strong>Sensor simulation이 필요한 이유</strong></li>
</ul>
<p>Isaac Sim 강의 흐름에서 camera, depth, lidar, contact sensor, IMU를 다루는 이유는 perception과 control을 실제 로봇 없이 검증하기 위해서다. Camera는 RGB image와 depth를 만들고, RTX lidar는 point cloud나 scan 정보를 만들며, contact sensor는 grasp나 충돌 상태를 확인하는 데 쓰인다. 이 sensor output이 ROS2 bridge나 Python API를 통해 perception pipeline으로 들어가면 실제 로봇 실험 전 디지털 환경에서 알고리즘을 검증할 수 있다.</p>
<ul>
<li><strong>Pick and Place로 이어지는 구조</strong></li>
</ul>
<p>Isaac Sim의 pick-and-place 예제는 로봇 model, gripper, task definition, controller가 함께 필요하다. 로봇은 articulation으로 움직이고, gripper는 end-effector로 조립되며, task는 pick target과 place target을 제공하고, controller는 motion policy나 RMPFlow 같은 방식으로 joint command를 만든다. 따라서 Isaac Sim에서 pick-and-place를 본다는 것은 “물체가 움직인다”보다 simulation scene, physics, robot controller, sensor feedback이 함께 맞물리는지를 보는 것이다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Isaac Sim은 센서, 물체, 로봇 제어, 물리 환경을 한 장면 안에서 검증하는 로봇 시뮬레이션 환경이다.</p>
<h2 id="12-디지털-트윈과-usd">1.2. 디지털 트윈과 USD</h2>
<h3 id="121-학습-목적">1.2.1. 학습 목적</h3>
<p>디지털 트윈은 현실의 로봇, 설비, 공정을 가상 공간에 복제하고 현실과 가상의 상태를 연결하는 기술이다. 로봇 개발에서는 실제 하드웨어 실험에 시간과 비용이 많이 들고, 실수로 로봇이나 설비가 손상될 수 있다. 또한 같은 실험 조건을 반복하기 어렵다.</p>
<p>디지털 트윈은 이런 문제를 줄이기 위해 현실과 유사한 가상 환경을 만들고, 그 안에서 배치, 센서, 물리, 제어, 공정 흐름을 미리 실험하게 한다. 단순 3D 모델이 아니라 물리적 속성, 센서 특성, 데이터 연결까지 포함하는 가상 시스템이다.</p>
<h3 id="122-디지털-트윈의-구성-조건">1.2.2. 디지털 트윈의 구성 조건</h3>
<p>디지털 트윈이 의미 있으려면 몇 가지 조건이 필요하다. 첫째, 기하학적 구조가 현실과 맞아야 한다. 로봇과 설비의 크기, 위치, 회전, 연결 관계가 실제와 다르면 시뮬레이션 결과도 의미가 약해진다.</p>
<p>둘째, 물리 속성이 반영되어야 한다. 질량, 무게 중심, 마찰, 충돌, 관성, joint constraint가 현실과 비슷해야 로봇 동작과 접촉 결과를 검증할 수 있다.</p>
<p>셋째, 센서가 시뮬레이션되어야 한다. 카메라, depth, LiDAR, IMU 같은 센서가 실제와 유사한 방식으로 데이터를 만들어야 perception 알고리즘을 검증할 수 있다.</p>
<p>넷째, 현실 시스템과 연결될 수 있어야 한다. 현실의 센서 데이터가 가상 환경으로 들어오거나, 가상 실험 결과가 실제 제어 전략으로 이어질 수 있어야 디지털 트윈의 가치가 커진다.</p>
<h3 id="123-omniverse와-isaac-sim">1.2.3. Omniverse와 Isaac Sim</h3>
<p>Omniverse는 실시간 3D 협업과 시뮬레이션을 위한 플랫폼이고, Isaac Sim은 그 위에서 로보틱스 시뮬레이션을 수행하는 애플리케이션이다. Omniverse는 여러 DCC 도구와 데이터를 연결하고, Isaac Sim은 로봇, 센서, 물리, ROS2 연동을 제공한다.</p>
<p>이 구조에서 Omniverse는 데이터와 협업 플랫폼, Isaac Sim은 로봇 실험 환경으로 이해할 수 있다. 즉 Isaac Sim은 디지털 트윈을 실제 로봇 개발에 적용하기 위한 실행 환경이다.</p>
<h3 id="124-usd와-openusd">1.2.4. USD와 OpenUSD</h3>
<p>USD는 Universal Scene Description의 약자로, 복잡한 3D scene을 구성하고 교환하기 위한 데이터 포맷이다. 로봇, 설비, 물체, 재질, 조명, 물리 속성, 계층 구조를 하나의 scene graph로 표현할 수 있다.</p>
<p>USD를 사용하는 이유는 여러 도구에서 만든 자산을 하나의 공통 형식으로 연결하기 위해서다. Blender, CAD, 시뮬레이터, 렌더러가 서로 다른 형식을 쓰면 공정 환경을 통합하기 어렵다. USD는 이런 자산들을 계층적으로 조합하고, reference나 layer를 통해 큰 scene을 관리할 수 있게 한다.</p>
<h3 id="125-nucleus와-협업-구조">1.2.5. Nucleus와 협업 구조</h3>
<p>Omniverse Nucleus는 USD 기반 scene과 자산을 중앙에서 관리하는 서버 역할을 한다. 여러 사용자가 같은 scene을 공유하거나, 외부 도구에서 만든 설비 모델을 Isaac Sim으로 가져올 수 있다. 이 구조는 공장 설비처럼 많은 자산이 포함된 디지털 트윈에서 중요하다.</p>
<h3 id="126-한-줄-정리">1.2.6. 한 줄 정리</h3>
<p>디지털 트윈은 현실의 로봇과 공정을 가상 환경에 물리적으로 재현하고, USD는 그 가상 세계를 구성하는 공통 scene description 형식이다.</p>
<h2 id="13-physx와-omnigraph">1.3. PhysX와 OmniGraph</h2>
<h3 id="131-학습-목적">1.3.1. 학습 목적</h3>
<p>로봇 시뮬레이션에서 물체가 보이는 것만으로는 충분하지 않다. 로봇이 물체를 밀고, 잡고, 충돌하고, 컨베이어 위에서 이동시키려면 물리 엔진이 필요하다. PhysX는 Isaac Sim에서 rigid body, collider, joint, contact, gravity 같은 물리 현상을 계산하는 엔진이다.</p>
<p>PhysX를 이해해야 하는 이유는 시뮬레이션 결과가 물리 설정에 의해 달라지기 때문이다. Collider가 없으면 물체가 서로 통과할 수 있고, rigid body 설정이 없으면 물체가 물리적으로 움직이지 않는다. Mass, friction, restitution, collision shape가 실제와 다르면 로봇 조작 실험도 현실과 다르게 나온다.</p>
<h3 id="132-collider-rigid-body-staticdynamic">1.3.2. Collider, Rigid Body, Static/Dynamic</h3>
<p>Collider는 충돌 판정을 위한 형상이다. 화면에 보이는 mesh가 복잡하더라도 collision 계산에는 단순화된 collider를 사용할 수 있다. Rigid body는 물리 시뮬레이션에서 힘과 충돌에 반응하는 물체다.</p>
<p>Static object는 움직이지 않는 물체로, 바닥이나 고정 설비처럼 환경 기준이 되는 대상에 사용한다. Dynamic object는 힘과 충돌에 따라 움직이는 물체다. 로봇이 집어 올릴 cube나 컨베이어 위의 물체는 dynamic object가 될 수 있다.</p>
<p>Trigger는 물리적으로 충돌을 막기보다 어떤 영역에 들어왔는지 감지하는 용도로 쓰인다. 공정 자동화에서는 물체가 특정 위치를 지났는지 감지하는 sensor 영역처럼 사용할 수 있다.</p>
<h3 id="133-fixed-joint와-부모-자식-관계">1.3.3. Fixed Joint와 부모-자식 관계</h3>
<p>공정 설비 배치에서는 world 좌표계와 local 좌표계를 구분해야 한다. 어떤 설비 위에 로봇을 올려놓거나, gripper를 robot flange에 붙이거나, 컨베이어 벨트를 특정 위치에 고정할 때 부모-자식 관계와 local transform이 중요하다.</p>
<p>Fixed joint는 두 물체를 물리적으로 고정된 관계로 묶는다. 예를 들어 로봇 base를 테이블 위에 고정하려면 base와 table 사이의 상대 위치가 정확해야 한다. local position을 잘못 설정하면 화면상 위치는 그럴듯해도 물리 연결이 어긋날 수 있다.</p>
<h3 id="134-omnigraph의-역할">1.3.4. OmniGraph의 역할</h3>
<p>OmniGraph는 Isaac Sim에서 node graph 방식으로 데이터 흐름과 동작을 구성하는 도구다. 코드로 모든 동작을 작성하지 않고, node를 연결해 센서 데이터, trigger, controller, ROS2 publish/subscribe 같은 흐름을 만들 수 있다.</p>
<p>OmniGraph를 배우는 이유는 공정 자동화가 단순 Python script만으로 구성되지 않기 때문이다. 센서 이벤트가 발생하면 물체를 이동시키고, 컨베이어 상태를 바꾸고, ROS2 메시지를 publish하는 흐름을 graph로 표현할 수 있다.</p>
<h3 id="135-한-줄-정리">1.3.5. 한 줄 정리</h3>
<p>PhysX는 Isaac Sim 안에서 물체와 로봇의 물리 반응을 계산하고, OmniGraph는 센서·이벤트·제어 흐름을 node graph로 구성하게 해 준다.</p>
<h2 id="14-isaac-python-scripting">1.4. Isaac Python Scripting</h2>
<h3 id="141-isaac-sim-python-scripting-api">1.4.1. Isaac Sim Python Scripting API</h3>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>Isaac Sim은 GUI로 scene을 구성할 수도 있지만, 반복 가능한 로봇 실험과 자동화 공정을 만들려면 Python script가 필요하다. Python scripting은 물체 생성, 로봇 import, controller 실행, 센서 데이터 획득, task 구성 과정을 코드로 재현하게 해 준다.</p>
<p>GUI 조작은 한 번의 실험에는 편하지만, 같은 환경을 다시 만들거나 여러 조건을 반복 비교하기 어렵다. Python script로 scene을 만들면 실험 조건을 코드로 관리할 수 있고, 로봇 동작을 자동화할 수 있다.</p>
<ul>
<li><strong>Stage와 Prim</strong></li>
</ul>
<p>Isaac Sim은 USD stage 위에 scene을 구성한다. Stage는 전체 3D 세계이고, prim은 stage 안의 객체 단위다. Sphere, Cube, Robot, Camera, Light 같은 요소가 prim으로 생성되고 배치된다.</p>
<p>Python API에서는 현재 stage를 가져오고, prim을 생성하거나 속성을 바꾸고, world를 step하면서 시뮬레이션을 진행할 수 있다. 이 구조를 이해하면 GUI에서 보이는 객체가 코드 안에서는 어떤 API 객체로 다뤄지는지 연결된다.</p>
<ul>
<li><strong>Core API와 World</strong></li>
</ul>
<p>Isaac Sim Core API는 World, Scene, Object, Robot, Controller, Task 같은 추상화를 제공한다. World는 시뮬레이션 전체를 관리하고, Scene은 world 안의 객체들을 관리한다. DynamicCuboid나 VisualCuboid 같은 객체를 scene에 추가할 수 있다.</p>
<p>World step은 시뮬레이션을 한 프레임 진행시키는 과정이다. 매 step마다 controller를 호출하고, 로봇 상태를 읽고, 센서 데이터를 갱신할 수 있다.</p>
<ul>
<li><strong>Controller와 Task</strong></li>
</ul>
<p>Controller는 로봇에게 어떤 action을 줄지 계산한다. 예를 들어 differential drive controller는 선속도와 각속도를 좌우 바퀴 속도로 변환한다. Manipulator controller는 end-effector 목표를 joint command로 바꾸는 역할을 할 수 있다.</p>
<p>Task는 환경과 목표를 정의한다. Pick-and-place task라면 물체의 초기 위치, 목표 위치, 로봇과 gripper, 성공 조건을 포함한다. Task를 분리하면 scene 구성과 제어 로직을 더 체계적으로 관리할 수 있다.</p>
<ul>
<li><strong>VS Code와 Jupyter 연동</strong></li>
</ul>
<p>수업 자료에서는 Isaac Sim과 VS Code, Jupyter Notebook 연동도 다룬다. 이는 긴 script를 작성하고 디버깅하거나, 실험적으로 API를 실행해 보기 위한 개발 환경 구성이다. 중요한 점은 Isaac Sim의 Python은 일반 시스템 Python과 다를 수 있으므로, Isaac Sim이 제공하는 Python 환경이나 extension 연동을 사용해야 한다는 것이다.</p>
<p><strong>Isaac Python Scripting 실습 정리</strong></p>
<ul>
<li><strong>Script는 GUI 조작을 재현 가능한 절차로 바꾼다</strong></li>
</ul>
<p>Isaac Sim 강의 코드에는 <code>hello_world.py</code>, <code>hello_world_extension.py</code>, <code>manipulator_tutorial.py</code> 같은 script와 extension 예제가 들어 있다. 이 코드들은 stage를 열고, prim을 추가하고, robot을 배치하고, world를 step하며, controller를 호출하는 작업을 Python으로 수행한다. GUI에서 한 번 만든 장면은 재현이 어렵지만, script로 작성하면 같은 scene과 같은 초기 조건을 반복 실행할 수 있다.</p>
<ul>
<li><strong>World, Scene, Object를 나누어 이해하기</strong></li>
</ul>
<p>Isaac Core API에서 <code>World</code>는 simulation loop와 physics step을 관리하는 상위 객체이고, <code>Scene</code>은 world 안에 배치된 robot, ground plane, object를 관리한다. Object나 robot prim은 scene 안에서 pose, scale, physics property를 가진다. 이 구분을 이해해야 “어디에 물체를 추가하는가”, “언제 simulation step을 돌리는가”, “어느 객체의 pose를 읽는가”가 명확해진다.</p>
<ul>
<li><strong>Extension 예제가 필요한 이유</strong></li>
</ul>
<p><code>hello_world_extension.py</code> 같은 예제는 단발 script와 extension의 차이를 보여 준다. Script는 실행 후 끝나는 자동화에 적합하고, extension은 Isaac Sim UI 안에서 panel, button, callback, long-running interaction을 제공할 때 필요하다. 로봇 설정 wizard나 teaching tool처럼 사용자가 시뮬레이터 안에서 반복 조작하는 기능은 extension 구조가 더 자연스럽다.</p>
<ul>
<li><strong>Manipulator tutorial의 의미</strong></li>
</ul>
<p><code>manipulator_tutorial.py</code> 계열 코드는 manipulator를 scene에 올리고 controller로 움직이는 흐름을 보여 준다. 여기서 script는 단순히 로봇을 움직이는 명령 모음이 아니라, scene 구성, robot articulation 접근, controller 생성, target pose 또는 task 설정, simulation step 실행을 하나의 절차로 묶는다. 이 구조가 이후 Isaac Pick and Place, factory automation, sensor data generation으로 확장된다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Isaac Sim Python Scripting API는 GUI로 만든 로봇 시뮬레이션을 코드로 재현하고, 물체 생성부터 controller와 task 실행까지 자동화하게 해 주는 도구다.</p>
<h3 id="142-isaac-python-scripting-핵심-코드-인용">1.4.2. Isaac Python Scripting 핵심 코드 인용</h3>
<p>Isaac Sim scripting은 world, scene, prim을 코드로 구성하는 방식이다. GUI에서 배치한 장면을 코드로 재현할 수 있어야 실험 조건을 반복할 수 있다.</p>
<pre><code class="language-python">world = self.get_world()
world.scene.add_default_ground_plane()

franka = world.scene.add(
    Franka(prim_path=&quot;/World/Fancy_Franka&quot;, name=&quot;fancy_franka&quot;)
)

world.scene.add(DynamicCuboid(
    prim_path=&quot;/World/random_cube&quot;,
    name=&quot;fancy_cube&quot;,
    position=np.array([0.3, 0.3, 0.3]),
    scale=np.array([0.0515, 0.0515, 0.0515]),
    color=np.array([0, 0, 1.0]),
))</code></pre>
<p><code>World</code>는 simulation loop와 physics step을 관리하고, <code>Scene</code>은 world 안의 robot과 object를 관리한다. <code>prim_path</code>는 USD stage 안의 객체 주소다. 같은 화면에 보이는 robot과 cube도 내부적으로는 <code>/World/...</code> 경로를 가진 prim으로 관리된다.</p>
<p>이 코드가 digital twin 개념과 연결되는 이유는 Isaac Sim이 단순한 3D 뷰어가 아니라 로봇, 물체, 물리, 센서를 가진 가상 세계이기 때문이다. ROS2 bridge를 붙이면 Isaac scene의 robot state와 sensor data가 ROS topic/action/service로 연결되고, MoveIt이나 perception pipeline을 실제 장비 없이 먼저 검증할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Robotics] 2. Robot Motion Tool 정리]]></title>
            <link>https://velog.io/@jack_7711/Robotics-2.-Robot-Motion-Tool-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Robotics-2.-Robot-Motion-Tool-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 22 Jun 2026 04:18:32 GMT</pubDate>
            <description><![CDATA[<h1 id="0-전체-내용-요약과-키워드">0. 전체 내용 요약과 키워드</h1>
<p>이 문서는 로봇의 구조를 정의하고, 그 구조를 실제 움직임으로 연결하는 과정을 정리한다. URDF/Xacro는 link, joint, visual, collision, inertial 정보를 통해 로봇의 몸과 운동학적 tree를 만든다. RViz는 이 모델과 TF, joint state, planning 결과를 시각화하고, Gazebo와 ros2_control은 물리 시뮬레이션과 controller 실행을 연결한다.</p>
<p>MoveIt 부분은 로봇 모델을 바탕으로 planning group, end-effector, planning scene, collision object, trajectory planning, controller execution이 어떻게 이어지는지 설명한다. 실습 코드는 <code>/joint_states</code>, <code>/collision_object</code>, STT topic, MoveItPy planning pipeline, gripper 제어, pick-and-place sequence를 통해 “모델이 보인다”에서 “안전하게 계획하고 실행한다”로 넘어가는 원리를 보여 준다.</p>
<p><strong>키워드</strong>: URDF, Xacro, link, joint, visual, collision, inertial, TF, RViz, Gazebo, ros2_control, controller, joint_states, MoveIt, planning group, end-effector, planning scene, collision object, trajectory, OMPL, Pilz, pick-and-place, gripper, STT, Doosan robot</p>
<h1 id="1-urdf와-xacro">1. URDF와 Xacro</h1>
<h2 id="11-urdf와-xacro-기본-구조">1.1. URDF와 Xacro 기본 구조</h2>
<h3 id="111-기본-개념">1.1.1. 기본 개념</h3>
<p>URDF는 로봇의 구조를 XML 형식으로 표현하는 파일이다. URDF는 로봇의 링크와 조인트, 시각 형상, 충돌 형상, 관성 정보를 정의한다. Xacro는 URDF를 더 효율적으로 작성하기 위한 매크로 언어다. 반복되는 구조를 줄이고 parameter를 사용해 모델을 관리하기 쉽게 만든다.</p>
<h3 id="112-link와-joint">1.1.2. Link와 Joint</h3>
<p>URDF에서 link는 로봇의 강체 부분을 의미하고, joint는 link와 link를 연결하는 관절을 의미한다. Joint에는 fixed, revolute, continuous, prismatic 같은 종류가 있다. Revolute joint는 제한된 범위 안에서 회전하고, prismatic joint는 직선 방향으로 이동한다.</p>
<p>Joint에는 parent link와 child link가 있으며, origin과 axis, limit 정보를 가진다. 이 관계가 로봇의 운동학적 구조를 만든다.</p>
<h3 id="113-visual-collision-inertial">1.1.3. Visual, Collision, Inertial</h3>
<p>URDF에서 visual, collision, inertial은 서로 다른 목적을 가진다. Visual은 RViz나 시뮬레이터에서 사람이 보는 모양이다. Collision은 충돌 검사에 사용하는 형상이다. Inertial은 물리 시뮬레이션에서 질량과 관성 계산에 사용된다.</p>
<p>이 세 정보를 구분하지 않고 visual만 잘 만들면 로봇이 화면에는 보이지만 planning이나 simulation에서는 문제가 생길 수 있다.</p>
<h3 id="114-moveit과-gazebo에서의-의미">1.1.4. MoveIt과 Gazebo에서의 의미</h3>
<p>MoveIt은 링크, 조인트, joint limit, collision geometry를 이용해 planning scene과 collision checking을 구성한다. Gazebo는 collision과 inertial 정보를 이용해 물리 시뮬레이션을 수행한다. RViz는 visual과 TF를 바탕으로 로봇 상태를 시각화한다.</p>
<p>하나의 URDF가 여러 도구의 공통 기반이 되는 것이다.</p>
<h3 id="115-xacro의-필요성">1.1.5. Xacro의 필요성</h3>
<p>로봇 모델이 커질수록 같은 형태의 링크나 joint가 반복된다. 매번 XML을 복사하면 관리가 어렵다. Xacro를 사용하면 길이, 질량, 색상, joint limit 같은 값을 변수로 두고 재사용할 수 있다.</p>
<h3 id="116-실습에서-봐야-하는-부분">1.1.6. 실습에서 봐야 하는 부분</h3>
<p>URDF/Xacro 실습에서는 링크 이름과 조인트 이름을 단순히 훑는 것이 아니라, parent-child 관계가 어떻게 로봇 tree를 만드는지 봐야 한다. Base link에서 시작해 각 link가 joint로 연결되고, end-effector까지 이어지는 구조가 로봇의 운동학적 체인이 된다.</p>
<p>또한 origin과 axis가 중요하다. Origin은 child link가 parent link 기준 어디에 놓이는지 정의하고, axis는 revolute/prismatic joint가 어느 방향으로 움직이는지 정의한다. Axis가 틀리면 로봇 관절이 의도와 다른 방향으로 움직인다.</p>
<h3 id="117-moveitgazebo-오류와의-연결">1.1.7. MoveIt/Gazebo 오류와의 연결</h3>
<p>URDF 오류는 뒤 단계에서 다른 문제처럼 나타날 수 있다. Collision geometry가 너무 크면 MoveIt planning이 계속 실패할 수 있고, inertial 정보가 부정확하면 Gazebo에서 로봇이 불안정하게 움직일 수 있다. Joint limit이 잘못되면 planning이 비현실적인 자세를 만들 수 있다.</p>
<p>따라서 URDF/Xacro는 단순 모델 파일이 아니라 로봇 시스템 전체의 공통 계약이다. 이 계약이 정확해야 RViz 시각화, Gazebo 물리 시뮬레이션, MoveIt motion planning이 모두 정상적으로 이어진다.</p>
<h3 id="118-urdfxacro-실습-정리">1.1.8. URDF/Xacro 실습 정리</h3>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>URDF/Xacro 실습에서 이해해야 하는 핵심은 로봇 모델링이 단순 3D 모델링이 아니라는 점이다. 로봇의 운동학, 충돌 검사, 물리 시뮬레이션, 시각화가 모두 모델 파일에 의존한다.</p>
<ul>
<li><strong>URDF는 로봇의 시각 모델만이 아니다</strong></li>
</ul>
<p><code>ROS/6차시/my_robot.urdf.xacro</code>, <code>move_urdf/src/urdf_r2d2/urdf/r2d2.urdf.xacro</code>, <code>gazebo_ws/src/simple_arm_description/urdf/simple_arm.urdf.xacro</code>는 URDF/Xacro가 로봇의 외형을 그리는 파일에 그치지 않는다는 점을 보여 준다. URDF에는 link, joint, parent-child 관계, joint axis, limit, visual, collision, inertial 정보가 들어간다. 이 정보는 RViz 시각화, TF tree, Gazebo physics, MoveIt collision checking, controller joint name 연결에 모두 사용된다.</p>
<ul>
<li><strong>Link와 Joint를 읽는 법</strong></li>
</ul>
<p>URDF를 읽을 때는 link 목록을 먼저 외우는 것보다 tree 구조를 봐야 한다. 어떤 link가 base이고, 어떤 joint가 parent link와 child link를 연결하며, joint type이 fixed인지 revolute인지 continuous인지 확인한다. Revolute joint라면 axis와 limit이 중요하다. Axis가 틀리면 로봇이 의도와 다른 방향으로 회전하고, limit이 틀리면 MoveIt과 Gazebo가 허용 범위를 다르게 이해할 수 있다.</p>
<ul>
<li><strong>Xacro를 쓰는 이유</strong></li>
</ul>
<p>Xacro는 반복되는 URDF 구조를 macro와 property로 줄이기 위해 쓴다. <code>simple_arm_core.urdf.xacro</code>, <code>simple_arm_gazebo.ros2_control.xacro</code>, <code>simple_arm_moveit.urdf.xacro</code>처럼 기능별 xacro를 나누면 같은 로봇의 기본 구조, Gazebo 제어 설정, MoveIt용 설정을 조합할 수 있다. 로봇이 커질수록 link와 joint를 순수 URDF로만 작성하면 중복이 많아지고 수정 실수가 늘어난다.</p>
<ul>
<li><strong>Gazebo와 MoveIt용 모델이 갈라지는 지점</strong></li>
</ul>
<p>Gazebo에서는 mass, inertia, collision, ros2_control plugin 같은 물리와 제어 정보가 중요하다. MoveIt에서는 planning group, collision geometry, end-effector link, joint limit, kinematics 설정이 중요하다. 같은 로봇 모델을 기반으로 하더라도 시뮬레이션과 planning이 요구하는 정보가 조금 다르기 때문에 xacro 파일을 기능별로 나누어 조립한다.</p>
<ul>
<li><strong>Doosan과 OnRobot 모델의 의미</strong></li>
</ul>
<p><code>doosan-robot2/urdf/m0609_isaac_sim.urdf</code>, <code>m0609.urdf</code>, <code>m0609.white.urdf</code>, <code>m0609.blue.urdf</code>는 같은 M0609 로봇이라도 사용 환경에 따라 모델 파일이 달라질 수 있음을 보여 준다. Isaac Sim용 URDF는 USD 변환과 simulation import를 고려해야 하고, 색상이나 mesh 경로가 다른 모델은 시각화 목적이 다를 수 있다.</p>
<p>OnRobot RG2 관련 xacro는 그리퍼가 로봇 arm과 별도 장치이지만 end-effector로 조립되어야 한다는 점을 보여 준다. Gripper 모델에는 손가락 link, gripper joint, collision geometry, tool frame이 들어가며, pick-and-place에서는 이 frame이 실제 grasp pose와 직접 연결된다.</p>
<ul>
<li><strong>실습에서 확인해야 할 것</strong></li>
</ul>
<p>URDF/Xacro 실습을 볼 때는 “모델이 보인다”에서 멈추면 안 된다. RViz에서 TF tree가 끊기지 않는지, Gazebo에서 물리적으로 안정적인지, MoveIt에서 collision checking이 합리적으로 되는지, controller 설정의 joint name과 URDF joint name이 일치하는지 확인해야 한다. 로봇 모델 파일은 이후 모든 실습의 기준 좌표와 구조를 정하는 출발점이다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>URDF/Xacro는 로봇의 몸을 ROS2, MoveIt, Gazebo, RViz가 함께 이해할 수 있는 형식으로 정의한다.</p>
<h2 id="12-rviz">1.2. RViz</h2>
<h3 id="121-기본-개념">1.2.1. 기본 개념</h3>
<p>RViz는 ROS2 시스템에서 로봇 상태, TF, sensor data, planning 결과를 시각화하는 도구다. RViz는 물리 시뮬레이터가 아니라 시각화 도구다. 이 차이를 이해해야 Gazebo와 RViz의 역할을 구분할 수 있다.</p>
<h3 id="122-시각화-대상">1.2.2. 시각화 대상</h3>
<p>RViz에서 자주 확인하는 것은 robot model, TF tree, joint state, point cloud, camera image, marker, planning scene, trajectory다. 로봇 모델이 제대로 보이지 않으면 URDF나 TF 문제일 수 있다. 센서 데이터가 엉뚱한 위치에 나타나면 frame 설정이 잘못되었을 가능성이 높다.</p>
<p>MoveIt planning 결과를 RViz에서 보면 계획된 경로가 장애물을 피하는지, end-effector가 목표 pose로 가는지 확인할 수 있다.</p>
<h3 id="123-디버깅-도구로서의-의미">1.2.3. 디버깅 도구로서의 의미</h3>
<p>RViz는 디버깅 도구로도 중요하다. 로봇이 움직이지 않을 때 controller 문제인지, planning 문제인지, TF 문제인지, joint state 문제인지 구분하려면 시각화가 필요하다.</p>
<p>TF frame이 끊겨 있으면 perception 결과가 표시되지 않을 수 있고, joint state가 publish되지 않으면 로봇 모델이 움직이지 않는다.</p>
<h3 id="124-moveit에서의-rviz">1.2.4. MoveIt에서의 RViz</h3>
<p>MoveIt을 사용할 때 RViz는 planning 결과를 확인하는 중심 도구가 된다. 사용자는 RViz에서 목표 pose를 지정하고, planning된 trajectory를 시각적으로 확인할 수 있다. 이때 보이는 경로는 단순 애니메이션이 아니라 MoveIt이 planning scene과 collision checking을 바탕으로 계산한 결과다.</p>
<p>RViz에서 로봇이 장애물을 통과하는 것처럼 보인다면 planning scene이나 collision object 설정을 확인해야 한다. End-effector 목표가 이상한 방향을 향한다면 TF나 pose orientation 문제가 있을 수 있다. RobotModel이 움직이지 않는다면 joint state가 publish되고 있는지 확인해야 한다.</p>
<h3 id="125-perception-결과-시각화">1.2.5. Perception 결과 시각화</h3>
<p>RViz는 CV 결과를 로봇 시스템 안에서 확인하는 데도 사용할 수 있다. Detection 결과는 marker나 bounding box로 표시할 수 있고, segmentation이나 depth 기반 obstacle은 point cloud나 marker array로 표현할 수 있다. 이렇게 하면 perception node가 publish한 결과가 실제 로봇 좌표계에서 어디에 놓이는지 확인할 수 있다.</p>
<p>따라서 RViz는 단순히 “로봇을 보는 화면”이 아니라 ROS2 topic, TF, robot state, planning result, perception output이 서로 맞는지 확인하는 통합 디버깅 도구다.</p>
<h3 id="126-rviz-실습-정리">1.2.6. RViz 실습 정리</h3>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>RViz 실습에서 중요한 것은 화면을 보는 것이 아니라 “무엇을 시각화하고 있는지”를 아는 것이다. RobotModel display는 URDF와 joint state를 기반으로 하고, TF display는 frame 관계를 보여 준다. Marker는 detection 결과나 목표 위치를 표시할 수 있다. MoveIt plugin은 planning scene과 trajectory를 시각화한다.</p>
<ul>
<li><strong>Display launch와 Gazebo launch의 차이</strong></li>
</ul>
<p><code>simple_arm_description/launch/display.launch.py</code> 또는 <code>display_launch.py</code>는 robot description을 RViz에 띄우고 joint state와 TF를 통해 로봇 모델이 어떻게 보이는지 확인하는 실행 파일이다. 반면 <code>gazebo_spawn.launch.py</code>는 Gazebo 물리 시뮬레이션에 로봇을 spawn한다. RViz는 물리를 계산하지 않고, ROS topic과 TF를 시각화한다.</p>
<ul>
<li><strong>RViz에서 RobotModel이 보이려면 필요한 것</strong></li>
</ul>
<p>RobotModel display는 <code>robot_description</code>에 들어간 URDF와 <code>/joint_states</code>를 함께 사용한다. URDF만 있으면 fixed pose의 모델은 보일 수 있지만, joint state가 없으면 현재 관절 위치가 반영되지 않는다. TF display는 frame 사이 변환이 끊기지 않았는지 보여 준다. 따라서 RViz에서 모델이 이상하게 보이면 URDF, joint state broadcaster, robot_state_publisher, TF frame 이름을 함께 확인해야 한다.</p>
<ul>
<li><strong>JointState publish와 spin_once 코드</strong></li>
</ul>
<p><code>move_urdf/src/urdf_r2d2/urdf_r2d2/state_publisher.py</code>는 RViz에서 움직이는 로봇 모델이 어떻게 만들어지는지 보여 준다. 핵심은 <code>/joint_states</code>에 해당하는 <code>JointState</code> message를 publish하고, 동시에 TF transform을 broadcast하는 것이다.</p>
<pre><code class="language-python">self.joint_pub = self.create_publisher(JointState, &#39;joint_states&#39;, qos_profile)
self.broadcaster = TransformBroadcaster(self, qos=qos_profile)</code></pre>
<pre><code class="language-python">while rclpy.ok():
    rclpy.spin_once(self)

    now = self.get_clock().now()
    joint_state.header.stamp = now.to_msg()
    joint_state.name = [&#39;swivel&#39;, &#39;tilt&#39;, &#39;periscope&#39;]
    joint_state.position = [swivel, tilt, height]

    self.joint_pub.publish(joint_state)
    self.broadcaster.sendTransform(odom_trans)
    loop_rate.sleep()</code></pre>
<p>여기서 <code>joint_state.name</code>은 URDF에 정의된 joint 이름과 맞아야 하고, <code>joint_state.position</code>은 각 joint의 현재 값을 담는다. RViz의 RobotModel은 이 값을 받아 관절 자세를 갱신한다. <code>rclpy.spin_once(self)</code>는 반복문 안에서 한 번씩 callback 처리를 허용하는 코드다. 이 예제에는 subscription callback이 많지 않더라도, ROS2 node가 timer, parameter, shutdown signal 같은 event를 처리할 수 있게 만드는 실행 지점이라는 의미가 있다.</p>
<ul>
<li><strong>MoveIt RViz plugin이 보여 주는 것</strong></li>
</ul>
<p><code>simple_arm_moveit/launch/moveit_rviz.launch.py</code>, <code>demo.launch.py</code>는 MoveIt 설정과 RViz를 함께 띄우는 구조다. MoveIt RViz plugin은 planning group, goal state, planning scene, collision object, planned trajectory를 시각화한다. 여기서 보이는 trajectory는 실제 실행 결과가 아니라 planner가 계산한 경로다. Gazebo나 실제 로봇에서 움직임을 확인하려면 controller 실행까지 연결되어야 한다.</p>
<ul>
<li><strong>RViz는 디버깅 도구다</strong></li>
</ul>
<p>RViz 실습에서 중요한 것은 화면이 예쁜지보다 어떤 topic과 frame을 보고 있는지다. Detection result는 marker나 image overlay로 볼 수 있고, depth point는 point cloud로 볼 수 있으며, MoveIt 목표 pose와 collision object는 planning scene으로 볼 수 있다. 로봇-CV 통합에서 RViz는 perception 결과가 robot frame 기준으로 맞게 변환되었는지 확인하는 핵심 디버깅 도구다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>RViz는 ROS2 시스템의 상태와 좌표계, planning 결과를 눈으로 확인하게 해 주는 시각화 도구다.</p>
<h2 id="13-gazebo와-ros2_control">1.3. Gazebo와 ros2_control</h2>
<h3 id="131-gazebo">1.3.1. Gazebo</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>Gazebo는 로봇을 실제 하드웨어 없이 물리 환경 안에서 실험할 수 있게 해 주는 시뮬레이터다. Gazebo를 사용하면 로봇 모델, 지면, 물체, 중력, 충돌, 마찰, 센서, controller를 함께 구성하고 실제 로봇에 적용하기 전에 알고리즘을 검증할 수 있다.</p>
<ul>
<li><strong>RViz와의 차이</strong></li>
</ul>
<p>Gazebo를 단순한 3D 뷰어로 생각하면 핵심을 놓친다. RViz는 로봇 상태와 센서 데이터를 시각화하는 데 강하지만, 물리 시뮬레이션을 직접 수행하는 도구는 아니다. Gazebo는 로봇이 물리 환경에서 어떻게 움직이는지 계산한다.</p>
<p>따라서 Gazebo에서는 collision geometry, mass, inertia, friction, controller 설정이 모두 중요하다.</p>
<ul>
<li><strong>실행 흐름</strong></li>
</ul>
<p>Gazebo에서 로봇을 움직이려면 URDF 모델만으로는 부족하다. 먼저 URDF/Xacro로 로봇 모델을 정의하고, Gazebo에서 모델을 spawn한다. 그 다음 controller manager와 controller를 실행하고, ROS2 topic이나 action으로 명령을 보내 joint가 움직이는지 확인한다.</p>
<p>이 흐름이 맞아야 “시뮬레이션 안에서 로봇이 제어된다”고 말할 수 있다.</p>
<ul>
<li><strong>Gazebo에서 확인해야 하는 요소</strong></li>
</ul>
<p>Gazebo 실습에서는 로봇이 화면에 보이는지만 확인하면 부족하다. 먼저 로봇 모델이 정상적으로 spawn되는지 확인해야 한다. 링크와 조인트가 URDF에서 의도한 구조대로 배치되어야 하고, joint limit이 실제 움직임과 맞아야 한다. 다음으로 물리 속성이 중요하다. Mass, inertia, collision geometry가 부정확하면 로봇이 비현실적으로 흔들리거나, 충돌 판정이 이상해지거나, controller 명령을 줘도 예상과 다른 움직임이 나온다.</p>
<p>또한 Gazebo에서는 controller와의 연결을 봐야 한다. 로봇 모델이 있어도 controller가 joint command를 전달하지 못하면 움직이지 않는다. <code>ros2_control</code> 설정, controller manager, joint trajectory controller, command/state interface가 맞물려야 한다. 따라서 Gazebo 실습은 “시뮬레이터 실행”이 아니라 모델, 물리, controller, ROS2 interface가 함께 맞는지 검증하는 과정이다.</p>
<ul>
<li><strong>MoveIt과의 관계</strong></li>
</ul>
<p>MoveIt은 경로를 계획하고, Gazebo는 그 경로가 물리 환경 안에서 어떻게 실행되는지 확인하게 한다. MoveIt에서 planning이 성공해도 Gazebo에서 controller가 제대로 설정되지 않으면 로봇은 움직이지 않을 수 있다. 반대로 Gazebo에서 로봇이 움직여도 collision geometry나 planning scene이 부정확하면 실제 planning 품질은 떨어질 수 있다.</p>
<p>따라서 Gazebo와 MoveIt은 역할이 다르지만 분리해서 볼 수 없다. MoveIt은 “어떻게 움직일지”를 계산하고, Gazebo는 “그 움직임이 시뮬레이션 환경에서 실제로 실행되는지”를 확인한다.</p>
<p><strong>Gazebo 실습 정리</strong></p>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>Gazebo 실습은 실제 로봇 제어 전에 문제를 발견하는 데 유용하다. Joint limit이 잘못되어 로봇이 비현실적으로 움직이거나, collision shape가 실제보다 커서 planning이 실패하거나, inertia가 부정확해 물리 움직임이 이상해질 수 있다.</p>
<p>Gazebo는 단순 결과 확인용 화면이 아니라, 로봇 모델과 controller, 물리 조건이 맞는지 검증하는 실험 환경이다.</p>
<ul>
<li><strong>Gazebo에 로봇을 spawn한다는 뜻</strong></li>
</ul>
<p><code>gazebo_ws/src/simple_arm_description/launch/gazebo_spawn.launch.py</code>와 강의 코드의 <code>gazebo_spawn_launch.py</code>는 URDF/Xacro로 정의한 로봇을 Gazebo simulation world에 올리는 흐름을 보여 준다. 여기서 spawn은 단순히 화면에 3D 모델을 띄우는 것이 아니라, Gazebo가 로봇의 link, joint, collision, inertia, controller interface를 simulation entity로 인식하게 만드는 과정이다.</p>
<p>로봇이 Gazebo에 보이더라도 모델이 올바르다고 볼 수는 없다. 링크 parent-child 관계가 맞아야 하고, joint axis와 limit이 맞아야 하며, collision geometry와 inertia가 물리적으로 말이 되어야 한다. 시뮬레이터에서 로봇이 흔들리거나 쓰러지거나 명령과 다르게 움직이면 대개 URDF/Xacro의 물리 속성, ros2_control 설정, controller 연결 중 하나를 확인해야 한다.</p>
<ul>
<li><strong>Simple Arm 실습 코드의 흐름</strong></li>
</ul>
<p><code>simple_arm_description</code> package에는 <code>simple_arm.urdf.xacro</code>, <code>simple_arm_gazebo.ros2_control.xacro</code>, <code>controllers.yaml</code>, <code>gazebo_spawn.launch.py</code>, <code>display.launch.py</code>가 함께 있다. 이 조합은 로봇 모델, Gazebo plugin/control interface, controller 설정, 실행 launch를 분리해서 관리하는 구조다.</p>
<p><code>trajectory_publisher.py</code>는 <code>/joint_trajectory_controller/joint_trajectory</code> topic으로 <code>JointTrajectory</code>를 한 번 publish한다. 메시지에는 <code>joint_names</code>와 <code>JointTrajectoryPoint</code>가 들어가며, point에는 목표 joint position과 <code>time_from_start</code>가 들어간다. 즉 Gazebo의 로봇을 움직이는 명령은 “각 joint가 언제 어느 위치에 도달해야 하는가”라는 trajectory 형태로 들어간다.</p>
<p><code>state_monitor.py</code>, <code>joint_monitor.py</code>는 <code>/joint_states</code>나 controller state를 읽어 현재 로봇 상태를 확인한다. <code>auto_stop.py</code>는 <code>joint3</code> 위치가 threshold를 넘으면 <code>/effort_controller/commands</code>로 0 torque 명령을 보내고 종료한다. 이 코드는 Gazebo 실습이 단순 움직임 확인이 아니라 state feedback을 읽고 안전 조건을 걸어 제어 흐름을 닫는 과정임을 보여 준다.</p>
<ul>
<li><strong>Gazebo와 RViz의 역할 차이</strong></li>
</ul>
<p><code>display.launch.py</code>는 주로 RViz에서 robot model과 joint state를 시각화하는 데 쓰이고, <code>gazebo_spawn.launch.py</code>는 Gazebo 물리 환경에 로봇을 올리는 데 쓰인다. RViz에서 보이는 것은 “로봇 상태를 시각화한 결과”이고, Gazebo에서 움직이는 것은 “물리와 controller가 연결된 simulation 결과”다. 따라서 RViz에서 모델이 정상이라고 해서 Gazebo 제어가 정상이라는 뜻은 아니다.</p>
<ul>
<li><strong>MoveIt과 함께 쓸 때 확인할 것</strong></li>
</ul>
<p><code>gazebo_ws/src/simple_arm_moveit/launch/gazebo_moveit.launch.py</code>는 Gazebo와 MoveIt을 함께 띄우는 구조다. 이때 MoveIt은 trajectory를 계획하고, ros2_control controller가 trajectory를 받아 Gazebo robot joint를 움직인다. 따라서 joint name, controller name, action interface, <code>/joint_states</code>, TF, robot description이 모두 같은 모델을 가리켜야 한다. 하나라도 어긋나면 planning은 되는데 실행이 안 되거나, Gazebo에서 움직임이 이상하게 보일 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Gazebo는 로봇 모델과 제어 명령이 물리 환경 안에서 실제처럼 동작하는지 확인하는 시뮬레이터다.</p>
<p><strong>ros2_control</strong></p>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>ros2_control은 ROS2에서 로봇의 하드웨어 인터페이스와 controller를 표준화하는 프레임워크다. 실제 로봇이든 Gazebo 안의 시뮬레이션 로봇이든, controller가 command를 보내고 state를 읽는 구조를 일관되게 만들기 위해 사용한다.</p>
<ul>
<li><strong>제어 구조</strong></li>
</ul>
<p>로봇 제어는 크게 세 층으로 볼 수 있다. 첫째, 상위 노드는 목표 위치나 속도 같은 명령을 만든다. 둘째, controller는 그 명령을 joint command로 변환하거나 trajectory를 따라가게 한다. 셋째, hardware interface는 실제 actuator나 시뮬레이터와 데이터를 주고받는다.</p>
<p>ros2_control은 이 층 사이의 인터페이스를 정리한다.</p>
<ul>
<li><strong>Command Interface와 State Interface</strong></li>
</ul>
<p>Command interface는 controller가 로봇에 보내는 명령이다. Position command, velocity command, effort command가 있을 수 있다. State interface는 로봇에서 읽어 오는 상태다. Joint position, velocity, effort가 대표적이다.</p>
<p>Controller는 state를 읽고 command를 보낸다. 이 구조를 명확히 해야 실제 하드웨어와 시뮬레이터를 같은 방식으로 다룰 수 있다.</p>
<ul>
<li><strong>Gazebo와의 연결</strong></li>
</ul>
<p>Gazebo와 연결할 때는 시뮬레이션 로봇이 실제 하드웨어처럼 동작하도록 plugin과 ros2_control 설정이 필요하다. Controller manager는 여러 controller를 로드하고 활성화한다.</p>
<p>Joint trajectory controller를 사용하면 MoveIt에서 생성한 trajectory를 받아 로봇 joint가 따라가도록 만들 수 있다.</p>
<ul>
<li><strong>Controller Manager</strong></li>
</ul>
<p>Controller manager는 controller를 로드하고, 설정하고, 활성화하는 역할을 한다. 로봇 시스템에서는 여러 controller가 동시에 존재할 수 있다. 예를 들어 joint state broadcaster는 현재 joint 상태를 publish하고, joint trajectory controller는 목표 trajectory를 받아 joint를 움직인다.</p>
<p>Controller가 로드되어 있다고 해서 항상 동작하는 것은 아니다. Configure와 activate 단계가 필요할 수 있고, controller가 요구하는 interface가 robot hardware description과 맞아야 한다. Command interface와 state interface가 맞지 않으면 controller가 활성화되지 않거나 명령을 보낼 수 없다.</p>
<ul>
<li><strong>MoveIt과의 관계</strong></li>
</ul>
<p>MoveIt은 trajectory를 계획하지만, 실제 joint에 명령을 보내는 계층은 controller다. 따라서 MoveIt 실습에서 planning은 성공하는데 로봇이 움직이지 않는다면 controller 설정을 확인해야 한다. Joint name이 맞는지, controller type이 맞는지, action interface가 연결되어 있는지, joint state가 publish되는지 확인해야 한다.</p>
<p>이 점을 이해하면 로봇 제어 흐름이 더 분명해진다. MoveIt은 경로를 만들고, ros2_control은 그 경로를 로봇 하드웨어나 Gazebo 시뮬레이션에 전달하는 실행 계층을 담당한다.</p>
<p><strong>ros2_control 실습 정리</strong></p>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>ros2_control을 이해하면 “MoveIt이 경로를 계획했다”와 “로봇이 실제로 움직였다” 사이에 controller 계층이 있다는 점이 보인다. Planning은 목표 trajectory를 만들지만, 그 trajectory를 실행하는 것은 controller다.</p>
<ul>
<li><strong>Controller 설정은 모델과 실행을 이어 준다</strong></li>
</ul>
<p><code>simple_arm_description/config/controllers.yaml</code>과 <code>simple_arm_moveit/config/ros2_controllers.yaml</code>, <code>moveit_controllers.yaml</code>은 ros2_control이 왜 필요한지 보여 준다. URDF/Xacro는 로봇의 구조를 설명하지만, 어떤 controller가 어떤 joint를 어떤 interface로 제어할지는 별도 설정이 필요하다. 이 설정이 있어야 trajectory command가 실제 joint command로 연결된다.</p>
<p><code>simple_arm_gazebo.ros2_control.xacro</code>는 Gazebo simulation에서 사용할 control interface를 로봇 모델에 붙이는 역할을 한다. 즉 Gazebo 속 로봇이 joint를 가진 물리 모델로만 존재하는 것이 아니라, controller manager가 접근할 수 있는 hardware interface를 가진 대상으로 등록된다.</p>
<ul>
<li><strong>Joint trajectory controller가 하는 일</strong></li>
</ul>
<p><code>trajectory_publisher.py</code>는 <code>/joint_trajectory_controller/joint_trajectory</code>로 <code>JointTrajectory</code> 메시지를 보낸다. 메시지의 핵심은 <code>joint_names</code>와 <code>points</code>다. <code>joint_names</code>가 controller 설정의 joint 이름과 맞지 않으면 controller는 목표를 해석할 수 없다. <code>points</code>에는 위치와 도달 시간이 들어가므로, controller는 단순 위치 명령이 아니라 시간 조건을 가진 trajectory를 따라가야 한다.</p>
<p>강의 코드의 <code>send_waypoint.py</code>와 <code>waypoint_action_follower.py</code>는 더 명확하게 <code>FollowJointTrajectory</code> action을 사용한다. <code>send_waypoint.py</code>는 먼저 controller state topic에서 현재 joint name과 현재 position을 읽고, 그 값을 시작점으로 넣은 뒤 target position을 다음 point로 넣어 action goal을 만든다. 이렇게 현재 상태를 시작점으로 넣는 이유는 controller가 갑자기 불연속 목표를 받지 않게 하기 위해서다.</p>
<ul>
<li><strong>State feedback이 필요한 이유</strong></li>
</ul>
<p><code>joint_monitor.py</code>, <code>state_monitor.py</code>, <code>controller_state_monitor.py</code>는 controller가 명령을 받았는지뿐 아니라 실제 상태가 어떻게 변하는지 확인하는 코드다. 로봇 제어에서는 publish가 성공했다고 제어가 성공한 것이 아니다. <code>/joint_states</code>나 controller state를 봐야 실제 joint position, velocity, error를 확인할 수 있다.</p>
<p><code>auto_stop.py</code>는 <code>joint3</code> 위치가 기준값을 넘으면 effort command를 0으로 보내는 안전 예제다. 이 코드는 feedback을 읽지 않는 제어가 왜 위험한지 보여 준다. 실제 로봇에서는 limit, collision, emergency stop, torque/current monitoring 같은 안전 조건이 반드시 state feedback과 연결되어야 한다.</p>
<ul>
<li><strong>MoveIt과 연결될 때의 의미</strong></li>
</ul>
<p>MoveIt은 경로를 계획하지만 실제 실행은 controller가 담당한다. <code>simple_arm_moveit</code>의 controller 설정과 Gazebo의 ros2_control 설정이 맞아야 MoveIt에서 생성한 trajectory가 <code>/follow_joint_trajectory</code> action을 통해 controller로 들어가고, controller가 Gazebo 또는 실제 robot joint를 움직인다. 따라서 MoveIt 실행 문제를 볼 때는 planner만 볼 것이 아니라 controller manager, joint state broadcaster, joint trajectory controller, action server 이름을 함께 확인해야 한다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>ros2_control은 로봇의 명령과 상태를 controller와 hardware interface로 연결하는 제어 프레임워크다.</p>
<p><strong>ros2_control 핵심 코드 인용</strong></p>
<p>URDF/Xacro와 Gazebo 제어의 연결은 <code>ros2_control</code> block에서 가장 분명하게 드러난다.</p>
<pre><code class="language-xml">&lt;ros2_control name=&quot;${name}&quot; type=&quot;system&quot;&gt;
  &lt;hardware&gt;
    &lt;plugin&gt;gazebo_ros2_control/GazeboSystem&lt;/plugin&gt;
  &lt;/hardware&gt;
  &lt;joint name=&quot;joint1_z&quot;&gt;
    &lt;command_interface name=&quot;position&quot;/&gt;
    &lt;state_interface name=&quot;position&quot;/&gt;
    &lt;state_interface name=&quot;velocity&quot;/&gt;
  &lt;/joint&gt;
&lt;/ros2_control&gt;</code></pre>
<p><code>joint1_z</code>는 로봇 모델의 joint 이름과 일치해야 한다. <code>command_interface</code>는 controller가 어떤 명령을 보낼 수 있는지, <code>state_interface</code>는 controller가 어떤 상태를 읽을 수 있는지 정한다. Gazebo plugin은 시뮬레이션 속 joint를 ros2_control hardware처럼 다룰 수 있게 만든다.</p>
<p>Controller YAML은 어떤 controller가 어떤 joint를 제어할지 정한다.</p>
<pre><code class="language-yaml">controller_manager:
  ros__parameters:
    update_rate: 100
    joint_state_broadcaster:
      type: joint_state_broadcaster/JointStateBroadcaster
    arm_controller:
      type: joint_trajectory_controller/JointTrajectoryController

arm_controller:
  ros__parameters:
    joints: [joint1_z, joint1_y, joint2, joint3]
    command_interfaces: [position]
    state_interfaces: [position, velocity]</code></pre>
<p>URDF/Xacro가 로봇의 몸과 관절 구조를 말한다면, controller 설정은 그 관절을 어떤 controller가 어떤 interface로 움직일지 말한다. MoveIt에서 planning이 성공해도 joint 이름, controller 이름, action interface가 맞지 않으면 trajectory는 실행되지 않는다. 그래서 RViz에서 모델이 보이는 것, Gazebo에서 물리가 도는 것, controller가 trajectory를 받는 것은 각각 따로 확인해야 한다.</p>
<h1 id="2-moveit">2. MoveIt</h1>
<h2 id="21-moveit-기본-구조와-핵심-코드">2.1. MoveIt 기본 구조와 핵심 코드</h2>
<h3 id="211-학습-목적">2.1.1. 학습 목적</h3>
<p>MoveIt은 로봇 팔의 motion planning을 위한 프레임워크다. 로봇 팔을 움직인다는 것은 단순히 목표 좌표를 주고 관절을 돌리는 일이 아니다. 로봇의 링크와 조인트 구조, 관절 제한, 현재 자세, 장애물, 자기 충돌, end-effector 목표 pose, controller 실행 가능성을 모두 고려해야 한다.</p>
<p>MoveIt은 이 복잡한 과정을 하나의 planning pipeline으로 묶어 준다. 따라서 MoveIt을 배운다는 것은 “로봇팔을 움직이는 명령어”를 배우는 것이 아니라, 목표 pose가 실제 실행 가능한 trajectory가 되기까지 어떤 단계가 필요한지 이해하는 것이다.</p>
<h3 id="212-moveit의-기본-구성">2.1.2. MoveIt의 기본 구성</h3>
<p>MoveIt은 로봇 모델을 기반으로 동작한다. 이 모델은 URDF/Xacro에서 정의된 링크, 조인트, joint limit, collision geometry를 사용한다. MoveIt Setup Assistant나 설정 패키지를 통해 planning group, end-effector, virtual joint, controller, kinematics solver 등을 정의한다.</p>
<p>Planning group은 함께 움직일 joint 묶음이다. 예를 들어 manipulator arm과 gripper를 분리할 수 있다. End-effector는 목표 pose를 지정할 기준이 되는 링크다. 로봇 팔을 특정 위치로 보내려면 end-effector 기준 pose를 설정하고, MoveIt이 그 pose를 만족하는 joint trajectory를 찾는다.</p>
<h3 id="213-motion-planning">2.1.3. Motion Planning</h3>
<p>Motion planning은 시작 상태에서 목표 상태까지 충돌 없이 이동할 수 있는 경로를 찾는 과정이다. 이 과정은 단순 직선 보간이 아니다. 로봇 팔은 여러 관절을 가진 고차원 configuration space에서 움직인다. 어떤 목표 pose는 관절 구조상 도달할 수 없고, 도달 가능하더라도 중간 경로에서 장애물이나 자기 몸과 충돌할 수 있다.</p>
<p>MoveIt은 planning scene을 사용해 로봇과 주변 환경을 모델링한다. Planning scene 안에는 현재 로봇 상태, 장애물, collision object, attached object가 포함된다. Planner는 이 정보를 바탕으로 충돌 없는 경로를 찾는다.</p>
<h3 id="214-collision-checking">2.1.4. Collision Checking</h3>
<p>Collision checking은 MoveIt의 핵심이다. 로봇이 움직이는 동안 링크끼리 충돌하지 않는지, 주변 물체와 부딪히지 않는지 검사한다. URDF의 collision geometry가 부정확하면 collision checking도 부정확해진다. 따라서 MoveIt 실습은 URDF/Xacro 실습과 분리될 수 없다.</p>
<p>충돌 검사는 단순히 장애물 회피만 의미하지 않는다. 로봇 팔은 자기 링크끼리 부딪힐 수도 있다. 또한 gripper가 물체를 잡은 후에는 그 물체가 attached object가 되어 로봇과 함께 움직인다고 봐야 한다. 이때 planning scene이 바뀌고, 충돌 검사도 바뀐다.</p>
<h3 id="215-trajectory-generation과-execution">2.1.5. Trajectory Generation과 Execution</h3>
<p>Planner가 찾은 경로는 실제 controller가 실행할 수 있는 trajectory로 변환되어야 한다. 단순한 위치의 나열만으로는 부족하다. 각 joint가 언제 어느 위치에 있어야 하는지, 속도와 가속도 제한을 만족하는지 고려해야 한다.</p>
<p>Trajectory execution 단계에서는 controller가 이 trajectory를 받아 로봇을 움직인다. 여기서 ros2_control과 joint trajectory controller가 연결된다. MoveIt이 planning을 성공했더라도 controller 설정이 맞지 않으면 실제 로봇이나 Gazebo 로봇은 움직이지 않을 수 있다.</p>
<h3 id="216-gazebo와-rviz와의-연결">2.1.6. Gazebo와 RViz와의 연결</h3>
<p>MoveIt 실습은 보통 RViz에서 planning 결과를 확인하고, Gazebo에서 물리 실행을 검증하는 흐름으로 이어진다. RViz는 planning scene과 trajectory를 시각화해 목표 pose와 경로가 적절한지 확인하게 해 준다. Gazebo는 로봇 모델과 controller가 물리 환경에서 실제로 동작하는지 검증한다.</p>
<p>MoveIt과 Gazebo를 함께 사용할 때는 robot model, controller, joint state, TF가 모두 맞아야 한다. 하나라도 어긋나면 planning은 되는데 실행이 안 되거나, RViz에서는 보이는데 Gazebo에서는 움직임이 이상한 문제가 생긴다.</p>
<h3 id="217-python으로-moveit-제어">2.1.7. Python으로 MoveIt 제어</h3>
<p>수업 흐름에서 MoveIt은 설정과 시각화뿐 아니라 Python script 제어로 확장된다. Python으로 MoveIt을 제어한다는 것은 목표 pose를 코드로 지정하고, planning을 호출하고, trajectory 실행을 요청하는 흐름을 이해하는 것이다.</p>
<p>이 단계에서는 MoveIt이 GUI 도구가 아니라 ROS2 시스템 안에서 호출 가능한 planning component라는 점이 중요하다. 즉 perception node가 물체 위치를 계산하면, Python node가 그 위치를 목표 pose로 만들고 MoveIt planning을 요청할 수 있다.</p>
<h3 id="218-waypoint와-ik-해의-문제">2.1.8. Waypoint와 IK 해의 문제</h3>
<p>MoveIt Python 제어 강의에서는 여러 waypoint를 순서대로 실행하는 구조가 등장한다. Waypoint는 로봇이 지나가야 할 중간 목표 pose다. 단순히 pose 목록을 만들고 차례대로 planning하면 로봇이 자연스럽게 움직일 것처럼 보이지만, 실제로는 관절이 크게 뒤집히거나 waypoint 사이 이동이 매끄럽지 않을 수 있다.</p>
<p>이 현상은 같은 end-effector pose를 만드는 관절 해가 여러 개 존재하기 때문에 발생한다. 이를 IK 해가 여러 개 존재한다고 한다. OMPL 같은 planner가 각 waypoint마다 그 순간 가능한 관절 자세 중 하나를 선택하면, 이전 waypoint에서의 관절 상태와 연속성이 깨질 수 있다. 결과적으로 end-effector 위치는 맞아도 관절이 불필요하게 크게 회전할 수 있다.</p>
<p>따라서 waypoint planning에서는 목표 pose만 보는 것이 아니라 관절 공간에서의 연속성, 경로의 부드러움, 이전 자세와의 변화량도 함께 봐야 한다. 이 내용은 MoveIt이 단순 pose solver가 아니라 planner pipeline을 통해 경로 품질을 다루는 시스템이라는 점을 보여 준다.</p>
<h3 id="219-planner-pipeline과-pilz">2.1.9. Planner Pipeline과 Pilz</h3>
<p>Planner pipeline은 MoveIt에서 어떤 계열의 planner를 사용하고, planning 요청을 어떤 방식으로 처리할지 정의하는 전체 체계다. Pipeline은 큰 틀이고, planner는 그 안에서 실제 경로를 계산하는 알고리즘이다.</p>
<p>OMPL은 sampling 기반 planning에 강하고 복잡한 환경에서 충돌 없는 경로를 찾는 데 사용된다. 하지만 산업용 로봇에서 직선 이동, 원호 이동, point-to-point 이동처럼 예측 가능한 motion primitive가 필요한 경우 Pilz planner가 적합할 수 있다. Pilz는 LIN, CIRC, PTP 같은 산업 로봇식 motion command를 제공한다.</p>
<p>이 차이를 이해하면 planner 선택이 단순 옵션이 아니라 작업 성격에 따른 설계 결정이라는 점이 보인다. 장애물 회피가 복잡한 환경에서는 sampling planner가 필요할 수 있고, 공정 자동화처럼 반복적이고 정형화된 움직임에서는 Pilz의 직관적인 motion primitive가 더 적합할 수 있다.</p>
<h3 id="2110-안전-workspace와-clamp">2.1.10. 안전 workspace와 clamp</h3>
<p>Python MoveIt 제어 강의에는 목표 좌표가 안전 범위를 벗어나면 제한 범위 안으로 잘라 넣는 clamp 구조가 등장한다. 이는 로봇이 물리적으로 위험한 공간으로 움직이지 않도록 방어하는 코드다.</p>
<p>목표 pose를 외부 입력이나 perception 결과에서 받을 때는 값이 항상 안전하다고 가정할 수 없다. 검출 오류, 좌표 변환 오류, 사용자 입력 실수로 로봇이 작업 공간 밖이나 충돌 위험 영역으로 이동하려 할 수 있다. 따라서 planning 전에 목표 위치를 안전 workspace로 제한하는 과정이 필요하다.</p>
<h3 id="2111-로봇cv-연결">2.1.11. 로봇/CV 연결</h3>
<p>MoveIt은 CV perception 결과와 로봇 control 사이의 다리 역할을 한다. YOLO가 물체의 bounding box를 찾거나 segmentation이 물체 영역을 찾으면, 이 결과는 depth와 TF 변환을 거쳐 로봇 기준 목표 pose가 될 수 있다. 또는 인식된 장애물을 planning scene의 collision object로 추가할 수 있다.</p>
<p>따라서 MoveIt은 perception 결과를 실제 로봇 행동으로 바꾸는 핵심 단계다. CV가 “무엇이 어디에 있는가”를 알려 주면, MoveIt은 “로봇이 어떻게 움직여야 하는가”를 계산한다.</p>
<h3 id="2112-moveit-실습-정리">2.1.12. MoveIt 실습 정리</h3>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>MoveIt 과제와 실습을 통해 확인한 핵심은 로봇팔 제어가 여러 계층의 연결이라는 점이다. URDF/Xacro는 로봇의 몸을 정의한다. TF는 좌표계를 연결한다. MoveIt은 planning scene과 collision checking으로 경로를 만든다. ros2_control과 controller는 trajectory를 실행한다. RViz는 이 과정을 시각화하고, Gazebo는 물리 환경에서 검증한다.</p>
<p>MoveIt은 “로봇을 목표점으로 보내는 기능”이 아니라, 로봇이 안전하게 움직일 수 있는지 계산하고 실행 가능한 trajectory로 만드는 motion planning 시스템이다.</p>
<ul>
<li><strong>MoveItPy 코드의 기본 실행 흐름</strong></li>
</ul>
<p><code>dsr_practice</code>의 <code>mp_basic.py</code>, <code>mp_waypoint.py</code>, <code>mp_waypoint_pilz.py</code>, <code>mp_waypoint_pilz_lin.py</code>는 MoveIt을 Python에서 어떻게 호출하는지 보여 준다. 공통 흐름은 <code>MoveItPy</code> 인스턴스를 만들고, <code>get_planning_component(&quot;manipulator&quot;)</code>로 planning group을 가져온 뒤, 현재 상태를 시작 상태로 설정하고, 목표 joint state나 end-effector pose를 goal로 설정하고, <code>plan()</code>을 호출한 다음 <code>robot.execute()</code>로 trajectory를 실행하는 구조다.</p>
<p>이 흐름에서 <code>GROUP_NAME</code>, <code>BASE_FRAME</code>, <code>EE_LINK</code>는 단순 상수가 아니다. <code>GROUP_NAME</code>은 SRDF에서 정의한 planning group과 일치해야 하고, <code>BASE_FRAME</code>은 목표 pose를 해석할 기준 좌표계이며, <code>EE_LINK</code>는 목표 pose를 맞출 end-effector link다. 이 셋이 URDF/SRDF와 맞지 않으면 planner는 목표를 제대로 해석할 수 없다.</p>
<ul>
<li><strong>안전 작업영역 clamp가 들어가는 이유</strong></li>
</ul>
<p><code>mp_waypoint.py</code> 계열 코드에는 <code>SAFE_X_MIN</code>, <code>SAFE_Y_MIN</code>, <code>SAFE_Y_MAX</code>, <code>SAFE_Z_MIN</code>과 <code>clamp_to_safe_workspace()</code>가 반복해서 등장한다. 이 함수는 목표 pose가 작업 가능한 범위를 벗어나면 x, y, z를 안전 범위 안으로 잘라 넣는다.</p>
<p>이 처리가 필요한 이유는 perception 결과나 사용자 입력이 항상 안전하다고 볼 수 없기 때문이다. 카메라 좌표 변환이 틀리거나, 음성 명령이 잘못 해석되거나, waypoint 값을 잘못 넣으면 로봇이 바닥이나 자기 몸체, 작업대 밖으로 움직이려 할 수 있다. Clamp는 planning을 시작하기 전 목표 자체를 제한해 위험한 목표가 planner로 들어가는 것을 막는다.</p>
<ul>
<li><strong>Waypoint planning에서 IK 문제가 드러나는 이유</strong></li>
</ul>
<p><code>mp_waypoint.py</code>는 여러 pose waypoint를 순서대로 넣어 planning하고 실행한다. 겉으로는 end-effector가 점들을 따라가면 되는 문제처럼 보이지만, 실제로는 각 pose마다 여러 inverse kinematics 해가 존재할 수 있다. 같은 tool pose라도 팔꿈치 방향이나 wrist posture가 달라질 수 있기 때문이다.</p>
<p>OMPL 기반 planner가 각 waypoint에서 가능한 해 중 하나를 선택하면, 이전 waypoint의 joint posture와 다음 waypoint의 joint posture가 매끄럽게 이어진다는 보장이 없다. 그래서 end-effector 위치는 맞지만 joint가 갑자기 크게 돌아가거나, waypoint 사이 움직임이 산업용 로봇 동작처럼 예측 가능하지 않을 수 있다. 이 문제가 강의에서 waypoint와 IK를 따로 다룬 이유다.</p>
<ul>
<li><strong>OMPL과 Pilz를 나누어 쓰는 이유</strong></li>
</ul>
<p><code>mp_waypoint_pilz.py</code>, <code>mp_waypoint_pilz_lin.py</code>는 <code>PlanRequestParameters</code>를 사용해 planning pipeline과 planner id를 명시한다. HOME 이동에는 <code>ompl</code>과 <code>RRTConnect</code>를 쓰고, waypoint 이동에는 <code>pilz_industrial_motion_planner</code>와 <code>PTP</code> 또는 <code>LIN</code>을 사용한다.</p>
<p>OMPL은 복잡한 configuration space에서 충돌 없는 경로를 찾는 데 강하지만, 산업용 로봇에서 기대하는 직선 이동이나 point-to-point primitive를 항상 보장하는 방식은 아니다. Pilz는 <code>PTP</code>, <code>LIN</code>, <code>CIRC</code> 같은 산업용 motion primitive를 제공하므로 공정 동작처럼 예측 가능한 이동을 만들 때 적합하다. <code>LIN</code>은 tool center point가 직선에 가깝게 움직이게 하고, <code>PTP</code>는 joint 또는 point-to-point 이동에 초점을 둔다.</p>
<ul>
<li><strong>Collision object를 추가한다는 뜻</strong></li>
</ul>
<p><code>collision_obstacle.py</code>는 <code>moveit_msgs/CollisionObject</code>를 <code>/collision_object</code> topic으로 publish해 planning scene에 box 장애물을 추가한다. 코드에서는 <code>SolidPrimitive.BOX</code>로 크기를 정하고, <code>Pose</code>로 위치를 정한 뒤 <code>CollisionObject.ADD</code> operation을 설정한다.</p>
<p>여기서 중요한 점은 장애물을 단순 시각화 marker로 그리는 것이 아니라 planner가 실제로 피해야 할 collision object로 등록한다는 것이다. Planning scene에 들어간 장애물은 이후 경로 계산에서 충돌 검사 대상이 된다. 따라서 장애물의 <code>frame_id</code>, 크기, 위치가 정확해야 한다. frame이 틀리면 장애물이 엉뚱한 곳에 놓이고, 크기가 틀리면 안전 여유가 과하거나 부족해진다.</p>
<ul>
<li><strong>FollowJointTrajectory action과 MoveIt 실행</strong></li>
</ul>
<p>강의 코드의 <code>send_waypoint.py</code>, <code>waypoint_action_follower.py</code>는 controller와 통신할 때 <code>control_msgs/action/FollowJointTrajectory</code> action을 사용한다. <code>send_waypoint.py</code>는 먼저 <code>/arm_controller/state</code> 같은 controller state topic에서 현재 joint 이름과 위치를 읽고, 현재 위치를 trajectory의 첫 point로 넣은 뒤 target position을 다음 point로 넣는다.</p>
<p>이 구조는 controller 실행이 단순 publish가 아니라 action goal이라는 점을 보여 준다. Goal에는 전체 trajectory가 들어가고, controller는 이를 실행한 뒤 result status를 돌려준다. <code>waypoint_action_follower.py</code>는 여러 waypoint를 시간 간격으로 구성해 action server에 보내고, 실행이 끝나면 hold time 뒤 반복한다. MoveIt에서 생성된 trajectory도 결국 controller가 이해하는 trajectory/action 형태로 내려가야 실제 로봇이나 Gazebo가 움직인다.</p>
<ul>
<li><strong>Pick and Place 코드에서 MoveIt이 맡는 부분</strong></li>
</ul>
<p><code>pick_and_place.py</code>, <code>gear_assembly.py</code>는 MoveIt이 작업 전체를 혼자 해결하지 않는다는 점을 보여 준다. MoveIt은 pick pose, approach pose, retreat pose, place pose로 이동하는 motion planning과 execution을 담당한다. 반면 gripper 개폐는 <code>onrobot.py</code>의 RG2 제어 코드가 담당한다.</p>
<p>Pick sequence는 보통 위에서 접근하고, pick 높이까지 내려가고, gripper를 닫고, 다시 위로 올라가는 순서다. Place sequence는 place 위치 위로 이동하고, 내려가고, gripper를 열고, 후퇴한다. 이 순서를 나누는 이유는 물체와 충돌하지 않고 안정적으로 접근하기 위해서다. 단일 목표 pose로 바로 이동하면 주변 물체나 작업대와 충돌할 수 있고, grasp 전후의 안전 높이를 보장하기 어렵다.</p>
<ul>
<li><strong>실습 코드에서 MoveIt을 읽는 기준</strong></li>
</ul>
<p>MoveIt 실습 코드는 <code>plan()</code> 한 줄을 보는 것이 아니라 계획 이전과 이후를 함께 봐야 한다. 이전에는 URDF/SRDF, planning group, frame, goal pose, 안전 범위, planning scene이 있고, 이후에는 trajectory execution, controller action, gripper 동작, Gazebo/RViz 검증이 있다. 이 전체 흐름을 연결해야 MoveIt이 “목표 pose를 안전한 로봇 동작으로 바꾸는 계층”이라는 의미가 분명해진다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>MoveIt은 로봇 모델, planning scene, collision checking, trajectory generation, controller execution을 연결해 목표 pose를 안전한 로봇 움직임으로 바꾸는 motion planning 프레임워크다.</p>
<h3 id="2113-moveit-실습-코드-흐름">2.1.13. MoveIt 실습 코드 흐름</h3>
<p><strong>MoveItPy 코드: planning pipeline과 planner 선택</strong></p>
<p>MoveItPy 실습의 기본 흐름은 robot 객체, planning component, planning parameter, goal, plan, execute가 순서대로 연결되는 구조다.</p>
<pre><code class="language-python">robot = MoveItPy(node_name=&quot;moveit_py&quot;)
arm = robot.get_planning_component(GROUP_NAME)

home_params = PlanRequestParameters(robot)
home_params.planning_pipeline = &quot;ompl&quot;
home_params.planner_id = &quot;RRTConnect&quot;

pilz_params = PlanRequestParameters(robot)
pilz_params.planning_pipeline = &quot;pilz_industrial_motion_planner&quot;
pilz_params.planner_id = &quot;LIN&quot;</code></pre>
<p><code>GROUP_NAME</code>은 SRDF의 planning group과 맞아야 하고, <code>planning_pipeline</code>과 <code>planner_id</code>는 어떤 방식으로 경로를 만들지 정한다. OMPL은 충돌 없는 경로 탐색에 강하고, Pilz의 <code>LIN</code>은 tool center point가 직선에 가깝게 움직이는 산업용 motion primitive에 가깝다.</p>
<pre><code class="language-python">planning_component.set_start_state_to_current_state()
planning_component.set_goal_state(pose_stamped_msg=pose_goal, pose_link=EE_LINK)
plan_result = planning_component.plan(parameters=plan_parameters)
robot.execute(group_name=GROUP_NAME, robot_trajectory=plan_result.trajectory, blocking=True)</code></pre>
<p>이 코드는 MoveIt의 네 단계를 그대로 보여 준다. 현재 robot state를 시작점으로 잡고, end-effector pose를 goal로 주고, planner가 trajectory를 만든 뒤, controller 실행 계층으로 trajectory를 넘긴다. Planning과 execution이 분리되어 있기 때문에 plan이 성공해도 controller 설정이 틀리면 실제 로봇은 움직이지 않는다.</p>
<p><strong>Planning Scene 코드: collision object 등록</strong></p>
<p>Planning scene에 장애물을 넣는 코드는 시각화가 아니라 collision checking 대상을 등록하는 작업이다.</p>
<pre><code class="language-python">pub = node.create_publisher(CollisionObject, &quot;/collision_object&quot;, qos)

primitive = SolidPrimitive()
primitive.type = SolidPrimitive.BOX
primitive.dimensions = list(size_xyz)

box.primitives.append(primitive)
box.primitive_poses.append(pose)
box.operation = CollisionObject.ADD
pub.publish(box)</code></pre>
<p><code>SolidPrimitive.BOX</code>와 <code>dimensions</code>는 장애물의 모양과 크기, <code>pose</code>는 위치, <code>CollisionObject.ADD</code>는 planning scene에 추가한다는 명령이다. 이 object가 정확해야 MoveIt이 실제 장애물을 피해 경로를 계획한다. YOLO나 segmentation으로 얻은 물체 위치를 collision object로 넣을 때도 frame과 크기가 틀리면 planner가 잘못된 세계를 기준으로 판단한다.</p>
<p><strong>Planning scene 파이프라인: 장애물 정보를 어디로 날리고 누가 쓰는가</strong></p>
<p><code>collision_obstacle.py</code>의 장애물 등록 흐름은 <code>collision_obstacle node -&gt; /collision_object topic -&gt; MoveIt planning scene -&gt; collision checking -&gt; trajectory planning</code>으로 이어진다. 이때 publisher는 단순히 화면에 박스를 그리는 것이 아니라, MoveIt이 경로를 계산할 때 피해야 할 세계 모델을 보낸다.</p>
<pre><code class="language-python">qos = QoSProfile(
    history=HistoryPolicy.KEEP_LAST,
    depth=1,
    reliability=ReliabilityPolicy.RELIABLE,
    durability=DurabilityPolicy.TRANSIENT_LOCAL,
)
pub = node.create_publisher(CollisionObject, &quot;/collision_object&quot;, qos)</code></pre>
<pre><code class="language-python">box = CollisionObject()
box.id = object_id
box.header.frame_id = frame_id

primitive = SolidPrimitive()
primitive.type = SolidPrimitive.BOX
primitive.dimensions = list(size_xyz)

pose = Pose()
pose.position.x, pose.position.y, pose.position.z = pos_xyz
pose.orientation.w = 1.0

box.primitives.append(primitive)
box.primitive_poses.append(pose)
box.operation = CollisionObject.ADD

pub.publish(box)</code></pre>
<p>여기서 <code>frame_id</code>는 장애물 위치가 어떤 좌표계를 기준으로 해석되는지 정한다. 예를 들어 <code>base_link</code> 기준으로 보낸 box는 robot base에서 본 장애물이다. Perception 결과를 camera frame에서 얻었다면, 먼저 TF나 hand-eye calibration으로 base frame으로 변환한 뒤 <code>CollisionObject</code>를 만들어야 한다. 그렇지 않으면 MoveIt은 실제 장애물이 아닌 엉뚱한 위치의 장애물을 기준으로 경로를 피한다.</p>
<p>QoS를 <code>TRANSIENT_LOCAL</code>로 둔 것도 파이프라인 관점에서 중요하다. <code>/collision_object</code>를 publish한 순간 MoveIt 쪽 subscriber가 늦게 붙으면 일반 volatile topic에서는 메시지를 놓칠 수 있다. 하지만 collision object는 “한순간의 로그”가 아니라 planning scene 상태에 가깝다. 그래서 마지막 장애물 메시지를 보존해 late subscriber도 받을 수 있게 하는 설정이 필요하다.</p>
<p><strong>Pick and Place 코드: 접근, 집기, 후퇴의 순서</strong></p>
<p>Pick-and-place 코드는 motion planning과 gripper 제어가 분리된다는 점을 보여 준다.</p>
<pre><code class="language-python">gripper = RG(GRIPPER_NAME, TOOLCHARGER_IP, TOOLCHARGER_PORT)
gripper.move_gripper(GRIPPER_OPEN_WIDTH, GRIPPER_FORCE)

pose_goal.pose.position.z = pos[&quot;z&quot;] + APPROACH_OFFSET
plan_and_execute(robot, arm, logger, pose_goal=pose_goal, plan_parameters=pilz_params)

pose_goal.pose.position.z = pos[&quot;z&quot;]
plan_and_execute(robot, arm, logger, pose_goal=pose_goal, plan_parameters=pilz_params)

gripper.move_gripper(GRIPPER_CLOSE_WIDTH, GRIPPER_FORCE)</code></pre>
<p>MoveIt은 approach pose와 grasp pose까지의 robot arm trajectory를 만들고 실행한다. Gripper는 별도 TCP/Modbus 계층으로 열린다. 접근 높이를 둔 뒤 내려가서 잡는 이유는 목표 pose 하나로 바로 이동할 때 생길 수 있는 작업대 충돌, 물체 측면 충돌, 불안정한 grasp를 줄이기 위해서다.</p>
<p><strong>STT 코드: 음성을 제한된 로봇 명령으로 바꾸는 구조</strong></p>
<p>STT 제어는 음성을 바로 robot motion으로 넣지 않고 topic과 parser를 거쳐 제한된 명령으로 바꾼다.</p>
<pre><code class="language-python">self._pub = self.create_publisher(String, &quot;/stt_result&quot;, 10)
text = recognizer.recognize_google(audio, language=self._lang)
msg = String()
msg.data = text
self._pub.publish(msg)</code></pre>
<pre><code class="language-python">normalized = text.lower().replace(&quot; &quot;, &quot;&quot;)
for kw, cmd in KEYWORD_MAP.items():
    if kw in normalized:
        return cmd</code></pre>
<p>첫 번째 코드는 음성을 ROS2 message로 바꾸는 입력 계층이고, 두 번째 코드는 자유로운 문장을 제한된 robot command로 줄이는 안전 계층이다. 이 분리가 있어야 음성 인식 오류가 곧바로 위험한 pose 목표가 되지 않는다.</p>
<h2 id="22-planning-scene과-collision">2.2. Planning Scene과 Collision</h2>
<h3 id="221-planning-scene과-collision-checking-상세">2.2.1. Planning Scene과 Collision Checking 상세</h3>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>MoveIt은 실제 세계를 직접 보는 것이 아니라, 내부에 구성된 planning scene을 기준으로 경로를 계획한다. 실제 환경에 장애물이 있어도 planning scene에 반영되지 않으면 MoveIt은 그 장애물을 모른다. 반대로 실제로는 없는 장애물이 planning scene에 남아 있으면 MoveIt은 불필요하게 경로를 피하거나 planning에 실패할 수 있다.</p>
<p>따라서 planning scene은 단순 배경 정보가 아니라 MoveIt이 의사결정을 내리는 세계 모델이다. 로봇이 안전하게 움직이려면 이 세계 모델이 실제 환경과 최대한 일치해야 한다.</p>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>Planning scene은 MoveIt이 motion planning을 수행하기 위해 사용하는 가상 세계다. 여기에는 로봇의 현재 상태, 주변 장애물, collision object, attached object, joint state, frame 정보가 포함된다. 로봇이 안전하게 움직이려면 planning scene이 실제 환경을 충분히 반영해야 한다.</p>
<ul>
<li><strong>Collision Checking</strong></li>
</ul>
<p>Collision checking은 로봇이 움직이는 동안 자기 자신이나 주변 물체와 충돌하지 않는지 확인하는 과정이다. 로봇 팔은 여러 링크로 이루어져 있기 때문에 자기 충돌도 고려해야 한다. 팔꿈치 링크가 몸체와 부딪히거나, gripper가 팔의 다른 링크와 충돌할 수 있다.</p>
<p>외부 장애물과의 충돌도 planning scene에 있는 collision object를 통해 검사한다.</p>
<p>충돌 검사는 planning의 안전성을 결정한다. 목표 pose가 도달 가능하더라도 중간 경로에서 장애물과 충돌하면 실행할 수 없는 경로다. 또한 목표 지점 주변에서 gripper가 물체나 테이블과 부딪힐 수 있다. 따라서 motion planning은 단순히 시작점과 목표점을 잇는 문제가 아니라, 전체 이동 과정에서 충돌이 없는지 확인하는 문제다.</p>
<ul>
<li><strong>Collision Geometry</strong></li>
</ul>
<p>Collision geometry는 visual geometry와 다를 수 있다. Visual geometry는 사람이 보기 좋은 자세한 모델일 수 있지만, collision geometry는 계산을 위해 단순화된 박스, 실린더, sphere, convex mesh로 표현할 수 있다.</p>
<p>너무 복잡한 collision geometry는 계산 비용을 늘리고, 너무 부정확한 geometry는 잘못된 planning 결과를 낳는다.</p>
<ul>
<li><strong>Perception과의 연결</strong></li>
</ul>
<p>Planning scene이 중요한 이유는 perception 결과와 직접 연결될 수 있기 때문이다. 카메라나 depth sensor로 장애물을 인식하면, 그 결과를 planning scene에 collision object로 추가할 수 있다. 그러면 MoveIt은 그 장애물을 피하는 경로를 계획한다.</p>
<p>예를 들어 YOLO나 segmentation으로 작업 대상 주변의 물체를 인식하고, depth 정보를 이용해 3D 위치를 추정하면, 그 물체를 planning scene에 추가할 수 있다. 이때 인식 결과가 부정확하면 collision object 위치도 틀어지고, MoveIt은 잘못된 세계를 기준으로 경로를 계획한다.</p>
<p>따라서 perception과 planning scene 사이에는 좌표 변환과 신뢰도 검증이 필요하다. 카메라 frame에서 얻은 물체 위치를 robot base frame으로 변환하고, 물체 크기와 shape를 적절한 collision geometry로 표현해야 한다.</p>
<p><strong>Planning Scene과 Collision 실습 정리</strong></p>
<ul>
<li><strong>이해해야 할 점</strong></li>
</ul>
<p>Planning scene은 눈에 보이는 배경이 아니라 MoveIt이 실제로 알고 있는 세계다. 실제 환경에 장애물이 있어도 planning scene에 없으면 MoveIt은 그 장애물을 피하지 않는다. 반대로 실제로는 없는 장애물이 planning scene에 남아 있으면 MoveIt은 불필요하게 경로를 피하거나 planning에 실패할 수 있다.</p>
<p>Collision checking은 로봇 시스템에서 안전과 직결된다. 실습에서는 planning이 성공했는지뿐 아니라, 왜 특정 경로가 거부되었는지, 어떤 collision object가 영향을 주었는지 확인하는 습관이 필요하다.</p>
<ul>
<li><strong>CollisionObject 메시지의 구조</strong></li>
</ul>
<p><code>dsr_practice/dsr_practice/collision_obstacle.py</code>는 <code>moveit_msgs/msg/CollisionObject</code>를 만들어 planning scene에 box 장애물을 추가한다. 메시지에는 <code>id</code>, <code>header.frame_id</code>, primitive shape, primitive pose, operation이 들어간다. <code>SolidPrimitive.BOX</code>와 <code>dimensions</code>는 장애물의 크기를 정하고, <code>Pose</code>는 장애물이 기준 frame에서 어디에 있는지 정한다.</p>
<ul>
<li><strong>frame_id가 중요한 이유</strong></li>
</ul>
<p>Collision object의 위치는 항상 <code>frame_id</code> 기준으로 해석된다. 코드에서 <code>BASE_FRAME = &quot;base_link&quot;</code>를 쓰면 box 위치는 robot base 기준 좌표다. 만약 camera frame에서 얻은 좌표를 변환하지 않고 base frame 장애물로 넣으면 장애물이 실제와 다른 곳에 생긴다. 그러면 planner가 엉뚱한 곳을 피하거나 실제 장애물을 무시하게 된다.</p>
<ul>
<li><strong>QoS를 TRANSIENT_LOCAL로 두는 이유</strong></li>
</ul>
<p>장애물 publisher는 <code>ReliabilityPolicy.RELIABLE</code>, <code>DurabilityPolicy.TRANSIENT_LOCAL</code>, depth 1 QoS를 사용한다. Planning scene을 구독하는 쪽이 약간 늦게 붙더라도 마지막 collision object 메시지를 받을 수 있게 하기 위한 설정이다. 장애물 정보는 순간 로그가 아니라 planning scene 상태에 가까우므로, late subscriber가 놓치면 안 된다.</p>
<ul>
<li><strong>경유 waypoint가 생기는 이유</strong></li>
</ul>
<p><code>collision_obstacle.py</code>는 기본 waypoint 사이에 detour point를 넣어 장애물을 피하는 경로를 만든다. 이 실습에서 중요한 것은 장애물을 추가하면 planner가 알아서 항상 이상적인 경로를 만든다고 믿는 것이 아니다. 장애물 위치, planner 종류, planning time, 목표 pose, 안전 높이에 따라 planning 성공 여부와 경로 품질이 달라진다. 필요하면 사람이 작업 sequence를 안전한 중간 목표로 나누어야 한다.</p>
<ul>
<li><strong>Pick-and-place와 연결되는 의미</strong></li>
</ul>
<p>Pick-and-place에서 물체를 집은 뒤에는 그 물체가 robot에 붙은 attached object처럼 취급될 수 있다. 이때 planning scene은 단순히 주변 장애물 목록이 아니라, 로봇이 현재 무엇을 들고 있는지까지 반영해야 한다. 그래서 collision 관리는 MoveIt의 부가 기능이 아니라 안전한 manipulation을 위한 핵심 상태 관리다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Planning scene은 MoveIt이 알고 있는 세계이고, collision checking은 그 세계 안에서 안전한 경로를 찾기 위한 검사 과정이다.</p>
<h2 id="23-두산-로봇-pick-and-place-stt">2.3. 두산 로봇, Pick and Place, STT</h2>
<h3 id="231-두산-로봇과-실제-로봇-제어-기반">2.3.1. 두산 로봇과 실제 로봇 제어 기반</h3>
<ul>
<li><strong>왜 두산 로봇 기초를 따로 정리하는가</strong></li>
</ul>
<p>ROS2, MoveIt, Gazebo를 이해해도 실제 로봇을 다룰 때는 로봇 제조사에서 제공하는 구조와 제어 방식, 안전 모드, 네트워크 연결, bringup 절차를 알아야 한다. 두산 로봇 자료는 이론적인 ROS2 시스템이 실제 협동로봇과 만날 때 어떤 준비가 필요한지 보여 준다.</p>
<p>두산 로봇 수업 흐름은 단순히 로봇 팔을 움직이는 것에서 끝나지 않는다. 실제 하드웨어와 연결하려면 로봇 모델, 제어 모드, IP/host 설정, bringup launch, 로봇 상태 확인, 직접 교시 모드와 원격 제어 모드 전환 같은 절차가 함께 필요하다.</p>
<ul>
<li><strong>실제 로봇과 시뮬레이션의 차이</strong></li>
</ul>
<p>시뮬레이션에서는 로봇 모델과 controller가 맞으면 비교적 쉽게 움직임을 확인할 수 있다. 하지만 실제 로봇은 안전 상태, 모드 전환, 네트워크 연결, 비상정지 상태, 충돌 감지, 속도 제한 같은 조건을 만족해야 한다.</p>
<p>따라서 실제 로봇 제어에서는 명령을 보내기 전에 로봇이 어떤 모드에 있는지, 원격 명령을 받을 수 있는지, bringup이 정상적으로 되었는지 확인해야 한다. 이 구조를 이해하지 못하면 MoveIt이나 ROS2 node가 정상이어도 실제 로봇이 움직이지 않을 수 있다.</p>
<ul>
<li><strong>Bringup의 의미</strong></li>
</ul>
<p>Bringup은 로봇 하드웨어나 시뮬레이션 로봇을 ROS2 시스템 안으로 올리는 과정이다. 이 과정에서 robot description, controller, driver, joint state, TF, RViz 등이 함께 실행될 수 있다. 두산 로봇 bringup은 실제 m0609 같은 모델을 ROS2에서 제어 가능한 대상으로 만들기 위한 시작점이다.</p>
<p>Bringup launch에는 mode, model, host 같은 인자가 들어갈 수 있다. <code>mode</code>는 real/simulation 여부, <code>model</code>은 사용할 로봇 모델, <code>host</code>는 실제 로봇 제어기의 IP 주소와 연결된다. 이 설정은 단순 옵션이 아니라 로봇 시스템이 어떤 대상과 통신할지 결정한다.</p>
<ul>
<li><strong>로봇 모드와 서비스 호출</strong></li>
</ul>
<p>실제 로봇에서는 직접 교시 모드와 원격 제어 모드가 구분된다. 수업 자료에서는 로봇 모드 전환을 service call로 수행하는 흐름이 등장한다. 이 구조는 ROS2 service가 실제 로봇 상태 변경에도 사용될 수 있음을 보여 준다.</p>
<p>로봇 모드를 service로 바꾼다는 것은, 로봇 제어도 결국 ROS2 interface를 통해 추상화될 수 있다는 뜻이다. 단, 실제 하드웨어에서는 안전 상태와 권한이 함께 작동하므로 service call이 성공했다고 해서 무조건 로봇을 움직일 수 있는 것은 아니다.</p>
<ul>
<li><strong>MoveIt과 두산 로봇의 연결</strong></li>
</ul>
<p>MoveIt에서 계획한 trajectory를 실제 두산 로봇에 실행하려면 로봇 description, planning group, controller, driver 연결이 모두 맞아야 한다. 시뮬레이션에서 성공한 planning을 실제 로봇에 적용할 때는 속도, 가속도, workspace limit, 충돌 위험을 더 보수적으로 봐야 한다.</p>
<p>두산 로봇 자료는 MoveIt이 단순 시뮬레이션 도구가 아니라 실제 협동로봇 제어로 이어질 수 있다는 점을 보여 준다. 하지만 그 연결에는 bringup, mode 설정, controller, safety 확인이 함께 필요하다.</p>
<p><strong>Fallback 코드: 실행 환경이 달라져도 디버그 정보를 잃지 않는 구조</strong></p>
<p>두산 bringup 계층의 <code>dsr_bringup2/utils.py</code>에는 package가 source 실행인지 install 실행인지에 따라 git root를 찾는 fallback 코드가 들어 있다.</p>
<pre><code class="language-python">if git_root is None:
    git_root = find_git_root_for_package_symlink_install(here)
if git_root is None:
    for parent in here.parents:
        if parent.name == &quot;install&quot;:
            ws_root = parent.parent
            git_root = find_any_git_in_src(ws_root)
            break

if git_root is None:
    return {
        &quot;commit&quot;: &quot;unknown&quot;,
        &quot;branch&quot;: &quot;unknown&quot;,
        &quot;user&quot;: &quot;unknown&quot;,
        &quot;email&quot;: &quot;unknown&quot;,
    }</code></pre>
<p>이 코드는 로봇 제어 알고리즘 자체는 아니지만, 실습과 디버깅에서 중요하다. ROS2 package는 source tree에서 실행될 수도 있고, colcon build 뒤 install space에서 실행될 수도 있다. 실행 위치가 달라져도 commit, branch 같은 정보를 최대한 찾고, 끝내 찾지 못하면 <code>&quot;unknown&quot;</code>으로 안전하게 떨어진다. 즉 fallback은 “아무 값이나 넣는 임시 처리”가 아니라, 실행 환경 차이 때문에 node가 깨지지 않도록 하고 디버그 정보를 가능한 범위에서 보존하는 구조다.</p>
<p>설정 파일 읽기에서도 같은 방식이 쓰인다.</p>
<pre><code class="language-python">if not os.path.exists(yaml_path):
    print(f&quot;[dsr_controller2] YAML file not found: {yaml_path}&quot;)
    return 100

try:
    ...
    return update_rate
except Exception as e:
    print(f&quot;[dsr_controller2] Failed to read YAML: {e}&quot;)
    return 100</code></pre>
<p><code>update_rate</code> YAML을 읽지 못해도 기본값 <code>100</code>으로 돌아가게 한 것은 controller 설정을 읽는 과정에서 예외가 전체 bringup 실패로 번지는 것을 줄이기 위한 방어 코드다. 실제 로봇 시스템에서는 file path, package share 경로, install 방식이 자주 달라지므로 이런 fallback이 있어야 실습 환경 차이를 견딜 수 있다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>두산 로봇 기초는 ROS2와 MoveIt으로 만든 제어 흐름을 실제 협동로봇에 연결하기 위한 하드웨어 bringup, 모드 전환, 안전 조건, controller 연결을 다룬다.</p>
<p><strong>Pick and Place 작업 sequence</strong></p>
<ul>
<li><strong>학습 목적</strong></li>
</ul>
<p>Pick and place는 로봇 manipulation의 대표 작업이다. 로봇이 물체를 인식하고, 접근하고, gripper로 잡고, 목표 위치로 옮긴 뒤 놓는 전체 흐름을 포함한다. 이 작업은 perception, planning, control, gripper, collision checking이 모두 연결되어야 성립한다.</p>
<p>수업 후반의 Isaac Sim과 MoveIt 자료는 pick and place를 통해 로봇팔 시스템의 전체 연결 구조를 보여 준다.</p>
<ul>
<li><strong>작업 단계</strong></li>
</ul>
<p>Pick and place는 보통 다음 단계로 나뉜다.</p>
<ol>
<li>물체 위치를 파악한다.</li>
<li>Pre-grasp pose를 정한다.</li>
<li>End-effector가 물체에 접근한다.</li>
<li>Gripper를 닫아 물체를 잡는다.</li>
<li>물체를 들어 올린다.</li>
<li>목표 위치로 이동한다.</li>
<li>Gripper를 열어 물체를 놓는다.</li>
<li>로봇을 안전한 자세로 되돌린다.</li>
</ol>
<p>각 단계는 단순 위치 이동이 아니라 collision checking과 trajectory execution을 포함한다.</p>
<ul>
<li><strong>Gripper 장착과 URDF 변환</strong></li>
</ul>
<p>Isaac Sim pick-and-place 자료에서는 M0609 로봇에 OnRobot RG2 gripper를 장착하는 흐름이 등장한다. Xacro 파일을 URDF로 변환하고, mesh와 urdf 폴더를 정리한 뒤 Isaac Sim에서 import한다.</p>
<p>Gripper를 로봇에 붙이려면 단순히 모델을 화면에 배치하는 것으로는 부족하다. Gripper base link와 robot end-effector link의 연결 관계가 맞아야 하고, 물리적으로 함께 움직이도록 assembly나 joint 관계가 설정되어야 한다.</p>
<ul>
<li><strong>RMPFlow와 Controller</strong></li>
</ul>
<p>Isaac Sim에서는 manipulator 제어에 RMPFlow 같은 controller 설정이 사용될 수 있다. RMPFlow는 로봇의 motion policy를 계산해 end-effector 목표를 따라가도록 만드는 방식이다. 이때 robot description, joint limit, collision sphere, controller yaml 설정이 함께 사용된다.</p>
<p>Pick-and-place script에서는 물체 위치와 목표 위치를 task로 정의하고, controller가 매 step마다 로봇 action을 계산한다. 따라서 코드는 단순 순차 명령이 아니라 world, task, controller, robot, gripper가 반복 step 안에서 상호작용하는 구조다.</p>
<ul>
<li><strong>Perception과의 연결</strong></li>
</ul>
<p>초기 실습에서는 물체 위치를 코드로 정해둘 수 있지만, 실제 로봇에서는 CV perception이 물체 위치를 제공해야 한다. YOLO나 segmentation으로 물체를 찾고, depth와 TF를 통해 3D pose를 계산하면 pick target이 된다.</p>
<p>따라서 pick and place는 CV와 로봇 제어가 만나는 대표 예시다. 인식 결과가 부정확하면 접근 pose가 틀어지고, collision scene이 부정확하면 이동 중 충돌이 발생할 수 있다.</p>
<p><strong>Pick and Place 실습 정리</strong></p>
<ul>
<li><strong>Pick and Place는 하나의 pose 이동이 아니다</strong></li>
</ul>
<p><code>dsr_practice/dsr_practice/pick_and_place.py</code>와 <code>gear_assembly.py</code>는 pick-and-place가 단순히 pick pose와 place pose 두 점을 잇는 문제가 아님을 보여 준다. 실제 sequence는 home 이동, approach pose 이동, pick 높이 하강, gripper close, retreat, place approach, place 하강, gripper open, retreat로 나뉜다.</p>
<p>이렇게 나누는 이유는 충돌과 grasp 안정성 때문이다. 물체 바로 옆으로 직선 이동하면 작업대나 주변 물체와 부딪힐 수 있고, 위에서 접근하지 않으면 gripper finger가 물체를 밀어낼 수 있다. Approach offset은 물체 위 안전 높이에서 자세를 맞춘 뒤 수직으로 내려가게 해 grasp 실패 가능성을 줄인다.</p>
<ul>
<li><strong>MoveIt과 gripper의 책임 분리</strong></li>
</ul>
<p>Pick-and-place 코드에서 MoveItPy는 robot arm trajectory를 계획하고 실행한다. 반면 OnRobot RG2 gripper는 <code>onrobot.py</code>의 <code>RG</code> class가 Modbus/TCP 방식으로 제어한다. 코드에는 <code>GRIPPER_OPEN_WIDTH</code>, <code>GRIPPER_CLOSE_WIDTH</code>, <code>GRIPPER_FORCE</code> 같은 값이 따로 있으며, pick 순간에는 gripper를 닫고 place 순간에는 연다.</p>
<p>이 분리가 중요한 이유는 arm motion planning과 end-effector actuation이 서로 다른 문제이기 때문이다. MoveIt은 gripper가 어느 위치로 이동해야 하는지 계산하지만, 실제 손가락을 몇 mm 열고 어떤 힘으로 닫을지는 gripper driver가 처리한다. 둘을 task sequence에서 정확한 순서로 묶어야 실제 조립 작업이 된다.</p>
<ul>
<li><strong>Pilz를 사용하는 이유</strong></li>
</ul>
<p>Pick-and-place 코드에서는 <code>PlanRequestParameters</code>로 HOME 이동에는 OMPL/RRTConnect를 사용하고, 작업 pose 이동에는 Pilz PTP를 사용한다. 반복 공정에서는 “어딘가 충돌 없이 가기”보다 “예측 가능한 방식으로 접근하고 후퇴하기”가 더 중요할 때가 많다. 그래서 산업용 motion primitive를 제공하는 Pilz가 pick/place 구간에 적합하다.</p>
<ul>
<li><strong>Gear assembly로 확장되는 구조</strong></li>
</ul>
<p><code>gear_assembly.py</code>는 gear pick pose와 place pose를 task dictionary로 정의하고, 같은 planning helper와 gripper 제어를 사용해 조립 sequence를 수행한다. 여기서 task dictionary는 perception 결과로 대체될 수 있는 부분이다. 초기 실습에서는 pose가 코드에 고정되어 있지만, 실제 시스템에서는 YOLO/segmentation/depth/TF를 거쳐 계산된 pose가 이 자리에 들어간다.</p>
<ul>
<li><strong>CV와 연결되는 지점</strong></li>
</ul>
<p>Pick target을 사람이 코드에 넣으면 로봇은 정해진 위치의 물체만 집을 수 있다. CV가 연결되면 image에서 물체를 찾고, depth로 3D 위치를 계산하고, hand-eye calibration과 TF로 robot base 기준 pose를 만든다. 그 pose가 MoveIt의 pick pose가 되고, gripper 동작과 결합해 실제 pick-and-place가 된다. 따라서 이 문서는 MoveIt, depth camera calibration, object detection, segmentation과 함께 읽어야 한다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Pick and place는 물체 인식, 접근 pose, gripper 제어, motion planning, trajectory execution이 연결되어야 완성되는 로봇 manipulation 작업이다.</p>
<p><strong>STT 로봇 연동 구조</strong></p>
<ul>
<li><strong>왜 STT를 로봇과 연결하는가</strong></li>
</ul>
<p>STT는 Speech-to-Text의 약자로, 사람의 음성을 텍스트로 변환하는 기술이다. 로봇 제어에 STT를 연결하면 사용자가 키보드나 코드 대신 음성 명령으로 로봇에게 작업을 지시할 수 있다. 이는 인간-로봇 상호작용의 기본 형태 중 하나다.</p>
<p>수업 흐름에서는 STT node가 음성을 인식해 텍스트 topic을 publish하고, 다른 node가 이 텍스트를 subscribe해 로봇 명령으로 변환하는 구조를 다룬다. 이 구조는 ROS2 topic이 센서 데이터뿐 아니라 사용자 입력 이벤트에도 사용될 수 있음을 보여 준다.</p>
<ul>
<li><strong>STT Node 구조</strong></li>
</ul>
<p>STT node는 마이크 입력을 받고, Google Web Speech API 같은 음성 인식 엔진을 통해 텍스트로 변환한다. 변환된 텍스트는 <code>/stt_result</code> 같은 topic으로 publish된다. 이 topic을 다른 node가 subscribe하면 음성 명령을 로봇 제어 로직으로 연결할 수 있다.</p>
<p>STT node는 언어 설정, 마이크 장치, 소음 임계값, energy threshold 같은 parameter를 가져야 한다. 환경 소음이 크면 음성 감지가 잘못될 수 있으므로 시작 시 주변 소음을 측정해 threshold를 보정하는 구조가 사용된다.</p>
<ul>
<li><strong>텍스트를 로봇 명령으로 바꾸는 방식</strong></li>
</ul>
<p>음성 인식 결과는 사람이 말한 자연어 문장이다. 로봇은 이 문장을 그대로 이해하지 못하므로, 명령어로 정규화하는 단계가 필요하다. 예를 들어 “왼쪽으로 가”, “left”, “왼쪽” 같은 표현을 모두 <code>left</code> 명령으로 매핑할 수 있다.</p>
<p>이 과정에서는 띄어쓰기 제거, 대소문자 통일, 키워드 검색 같은 전처리가 사용된다. 인식 결과가 완벽하지 않을 수 있으므로, 명령 매핑은 가능한 입력 변형을 견딜 수 있게 설계해야 한다.</p>
<ul>
<li><strong>MoveIt과 STT Pick and Place</strong></li>
</ul>
<p>STT 결과를 로봇 팔 제어와 연결하면 음성 명령으로 home, left, right 같은 pose 이동을 수행할 수 있다. 더 나아가 pick and place 작업도 음성 명령으로 시작할 수 있다.</p>
<p>이 구조에서는 STT node가 perception이나 planning을 직접 수행하지 않는다. STT node는 사용자 의도를 텍스트로 바꾸고, robot control node가 그 텍스트를 명령으로 해석해 MoveIt planning이나 controller 실행을 호출한다. 역할이 분리되어야 음성 인식과 로봇 제어를 독립적으로 수정할 수 있다.</p>
<p><strong>STT 로봇 제어 실습 정리</strong></p>
<ul>
<li><strong>STT node는 음성을 topic으로 바꾼다</strong></li>
</ul>
<p><code>dsr_practice/dsr_practice/stt_node.py</code>는 microphone 입력을 받아 Google Web Speech API로 텍스트를 인식하고, 결과를 <code>/stt_result</code> topic에 <code>std_msgs/String</code>으로 publish한다. Parameter로 <code>language</code>, <code>device_index</code>, <code>energy_threshold</code>, <code>pause_threshold</code>, <code>phrase_time_limit</code>, <code>dynamic_energy</code>, <code>ambient_duration</code>를 선언한다.</p>
<p>이 parameter들이 필요한 이유는 음성 인식이 실행 환경에 민감하기 때문이다. 마이크 장치 번호가 다를 수 있고, 주변 소음에 따라 energy threshold가 달라질 수 있으며, 발화가 끝났다고 판단하는 pause threshold도 상황에 맞게 조절해야 한다. STT node는 로봇 제어를 직접 하지 않고, “음성 입력을 ROS2 text topic으로 변환하는 책임”만 가진다.</p>
<ul>
<li><strong>Robot control node는 text를 명령으로 해석한다</strong></li>
</ul>
<p><code>stt_robot_control.py</code>는 <code>/stt_result</code>를 subscribe하고, 들어온 문자열을 정규화한 뒤 keyword map으로 <code>home</code>, <code>left</code>, <code>right</code>, <code>forward</code>, <code>backward</code>, <code>up</code>, <code>down</code>, <code>stop</code> 같은 명령으로 바꾼다. 이 node는 MoveItPy를 사용해 현재 end-effector pose를 기준으로 5cm offset 이동을 만들거나, home joint constraint로 복귀 동작을 계획한다.</p>
<pre><code class="language-python">self.create_subscription(String, &quot;/stt_result&quot;, self._stt_cb, 10)

def _stt_cb(self, msg: String):
    cmd = _text_to_cmd(msg.data)
    if cmd is None:
        self.get_logger().debug(f&quot;매핑 없음: &#39;{msg.data}&#39;&quot;)
        return

    if cmd == &quot;stop&quot;:
        ...
    else:
        self._cmd_q.put(cmd)</code></pre>
<p>이 subscription callback은 음성 텍스트를 곧바로 motion으로 실행하지 않고, 먼저 제한된 명령으로 변환한 뒤 queue에 넣는다. <code>cmd is None</code>이면 실행하지 않고 돌아가므로, 인식된 문장이 keyword map에 없을 때 로봇이 임의로 움직이지 않는다.</p>
<pre><code class="language-python">executor = MultiThreadedExecutor()
executor.add_node(node)

try:
    executor.spin()
except KeyboardInterrupt:
    pass
finally:
    node.destroy_node()
    robot.shutdown()
    rclpy.shutdown()</code></pre>
<p>STT 제어 node도 <code>executor.spin()</code>이 있어야 <code>/stt_result</code> subscription callback이 계속 처리된다. MoveIt planning과 음성 callback, worker thread가 함께 있으므로 실행 루프를 명확히 두어야 node가 음성 입력을 기다리고, 들어온 명령을 queue에 넣고, robot motion으로 이어 갈 수 있다.</p>
<p>여기서 중요한 점은 STT 결과를 바로 로봇 명령으로 쓰지 않는다는 것이다. 음성 텍스트는 오인식될 수 있으므로 keyword map, valid command set, stop 처리, 안전 workspace clamp가 필요하다. 특히 이동 명령은 <code>SAFE_X_MIN</code>, <code>SAFE_Y_MIN</code>, <code>SAFE_Y_MAX</code>, <code>SAFE_Z_MIN</code>으로 제한되어 위험한 목표가 MoveIt에 들어가지 않도록 한다.</p>
<ul>
<li><strong>음성 명령과 MoveIt planning의 연결</strong></li>
</ul>
<p><code>stt_robot_control.py</code>는 음성 명령을 해석한 뒤 MoveIt planning component에 goal을 넣고 planning/execution을 수행한다. <code>left/right/up/down</code> 같은 명령은 절대 좌표 목표라기보다 현재 tool pose에서 offset을 더하는 jog command에 가깝다. 따라서 이 코드는 자연어 전체를 이해하는 시스템이 아니라, 제한된 명령어를 안전한 robot motion command로 변환하는 interface다.</p>
<ul>
<li><strong>STT Pick and Place의 의미</strong></li>
</ul>
<p><code>stt_pick_and_place.py</code>와 관련 launch 파일은 음성 인식 결과를 pick-and-place sequence의 trigger로 확장한다. 이 구조에서는 STT node가 perception이나 motion planning을 대신하지 않는다. STT는 사용자 의도를 text event로 바꾸고, task node가 그 event를 받아 MoveIt, gripper, safety logic을 조합한다.</p>
<ul>
<li><strong>실습에서 확인해야 할 것</strong></li>
</ul>
<p>STT 로봇 제어 실습은 음성 인식 정확도만 보는 과제가 아니다. 음성이 ROS2 topic으로 들어오고, command parser가 제한된 명령으로 해석하며, MoveIt이 안전 범위 안에서 계획하고, launch가 STT node와 robot control node를 함께 실행하는 전체 구조를 봐야 한다. 이렇게 나누어야 음성 UI가 로봇 제어의 위험한 직접 입력이 아니라 검증된 task trigger가 된다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>STT-로봇 연동은 음성 입력을 ROS2 topic으로 전달하고, 텍스트 명령을 로봇 pose 이동이나 pick-and-place 작업으로 변환하는 인간-로봇 상호작용 구조다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Robotics] 1. ROS2 개념 정리]]></title>
            <link>https://velog.io/@jack_7711/Robotics-1.-ROS2-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Robotics-1.-ROS2-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Mon, 22 Jun 2026 04:05:06 GMT</pubDate>
            <description><![CDATA[<h1 id="0-전체-내용-요약과-키워드">0. 전체 내용 요약과 키워드</h1>
<p>이 문서는 ROS2를 로봇 시스템을 구성하는 분산 미들웨어로 정리한다. 핵심은 로봇 기능을 하나의 큰 프로그램이 아니라 여러 node로 나누고, node 사이를 topic, service, action으로 연결하는 방식이다. Topic은 지속적으로 흐르는 데이터, service는 요청과 응답, action은 시간이 걸리는 목표 수행과 feedback/cancel을 담당한다.</p>
<p>실습 코드는 단순 문법보다 통신 파이프라인을 이해하는 데 초점이 있다. Publisher가 message를 어디로 publish하는지, subscriber가 어떤 callback으로 받는지, service client가 어떤 request를 보내고 server가 어떤 response를 채우는지, action client/server가 goal, feedback, result를 어떻게 주고받는지 확인한다. <code>spin</code>, <code>spin_once</code>, <code>spin_until_future_complete</code>, <code>MultiThreadedExecutor</code>는 생성된 통신 endpoint가 실제 callback으로 실행되게 하는 핵심 실행 구조다.</p>
<p><strong>키워드</strong>: ROS2, node, topic, publisher, subscriber, service, <code>.srv</code>, request, response, action, goal, feedback, result, cancel, callback, spin, executor, launch, parameter, workspace, package, interface, QoS, ROS graph</p>
<h1 id="1-ros2">1. ROS2</h1>
<h2 id="11-ros2-기본-구조">1.1. ROS2 기본 구조</h2>
<h3 id="111-학습-목적">1.1.1. 학습 목적</h3>
<p>ROS2는 로봇 시스템을 하나의 거대한 프로그램으로 만들지 않고, 여러 개의 독립된 실행 단위가 서로 통신하며 협력하도록 만드는 로봇 미들웨어다. 로봇은 센서 입력, 인식, 판단, 경로 계획, 제어, 시각화, 시뮬레이션이 동시에 움직이는 시스템이다. 이 모든 기능을 하나의 코드 안에 넣으면 구조가 복잡해지고, 어느 부분에서 문제가 생겼는지 찾기 어렵다.</p>
<p>ROS2의 핵심은 로봇 기능을 <code>node</code>로 나누고, node 사이를 <code>topic</code>, <code>service</code>, <code>action</code> 같은 통신 구조로 연결하는 것이다. 그래서 ROS2를 배운다는 것은 단순히 명령어를 외우는 것이 아니라, 로봇 시스템을 어떤 기능 단위로 나누고, 그 기능들을 어떤 통신 방식으로 다시 묶을지 이해하는 것이다.</p>
<p>수업 흐름에서도 ROS2는 뒤에 나오는 URDF, Gazebo, RViz, MoveIt, Isaac Sim을 이해하기 위한 기반이 된다. URDF는 로봇 모델을 정의하고, Gazebo는 그 모델을 물리 시뮬레이션 안에서 움직이며, RViz는 상태와 좌표계를 시각화하고, MoveIt은 motion planning을 수행한다. 이 모든 흐름은 ROS2 node와 message 통신 위에서 연결된다.</p>
<h3 id="112-node">1.1.2. Node</h3>
<p>Node는 ROS2 시스템의 기본 실행 단위다. 하나의 node는 하나의 역할을 갖는 것이 좋다. 예를 들어 카메라 이미지를 발행하는 node, 이미지를 받아 물체를 검출하는 node, 로봇 팔의 경로를 계획하는 node, controller에 명령을 보내는 node를 분리할 수 있다.</p>
<p>Node를 분리하면 각 기능을 독립적으로 실행하고 테스트할 수 있다. 또한 다른 프로젝트에서도 재사용하기 쉽다. 반대로 여러 기능을 한 node에 몰아넣으면 topic 흐름이 보이지 않고, 특정 기능만 교체하거나 디버깅하기 어렵다.</p>
<p>ROS2 실습에서 <code>ros2 node list</code>, <code>ros2 node info</code> 같은 명령을 사용하는 이유는 현재 시스템에 어떤 node가 있고, 각 node가 어떤 topic/service/action과 연결되는지 확인하기 위해서다. 단순히 node 이름을 보는 것이 아니라, 시스템의 기능 분해 구조를 읽는 과정이다.</p>
<h2 id="12-topic-service-action-통신">1.2. Topic, Service, Action 통신</h2>
<h3 id="121-topic-지속-데이터-통신">1.2.1. Topic: 지속 데이터 통신</h3>
<p>Topic은 지속적으로 흐르는 데이터에 적합한 통신 방식이다. Publisher는 topic에 message를 발행하고, subscriber는 topic을 구독해 message를 받는다. 센서 데이터, 카메라 이미지, 로봇 상태, joint state, object detection 결과처럼 계속 갱신되는 데이터는 topic으로 다루는 것이 자연스럽다.</p>
<p>Topic의 핵심은 비동기성과 느슨한 연결이다. Publisher는 subscriber가 누구인지 직접 알 필요가 없다. Subscriber도 publisher 내부 구현을 알 필요가 없다. 둘은 topic 이름과 message type만 맞으면 통신할 수 있다. 이 구조 덕분에 로봇 시스템은 센서 node, perception node, visualization node를 독립적으로 바꾸면서도 같은 topic을 기준으로 연결할 수 있다.</p>
<p>Topic 실습에서 중요한 것은 “메시지가 오고 간다”는 결과보다 어떤 데이터가 지속 흐름으로 설계되는지 판단하는 것이다. 예를 들어 Turtlesim에서 velocity command는 계속 publish될 수 있고, turtle pose도 계속 갱신된다. 로봇에서는 camera image, lidar scan, joint state, detection result가 topic으로 흐른다.</p>
<h3 id="122-service-요청과-응답-통신">1.2.2. Service: 요청과 응답 통신</h3>
<p>Service는 명확한 요청과 응답이 필요한 작업에 적합하다. Client가 request를 보내면 server가 response를 돌려준다. 예를 들어 특정 물품의 재고를 확인하거나, 결제를 승인하거나, 현재 설정값을 조회하거나, 특정 계산을 요청하는 작업은 service 구조가 잘 맞는다.</p>
<p>Service는 함수 호출처럼 보일 수 있지만 실제로는 node 사이의 통신이다. 따라서 server가 실행 중인지 확인해야 하고, 응답 실패나 지연 가능성도 고려해야 한다. 서비스가 준비되지 않았는데 client가 요청을 보내면 전체 흐름이 실패할 수 있다.</p>
<p>수업 과제에서 확인한 smart shop service 실습은 ROS2 service 구조를 잘 보여 준다. <code>order_manager</code> node는 <code>place_order</code> service server로 주문 요청을 받고, 내부적으로 <code>check_stock</code>, <code>authorize_payment</code>, <code>discount_server</code> 같은 다른 service에 의존한다. 즉 하나의 node가 server이면서 동시에 client가 될 수 있다. 실제 로봇 시스템에서도 하나의 작업 node가 다른 node의 기능을 요청하는 구조가 자주 등장한다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/2a665b0e-8544-47de-9e6a-b07163888ad7/image.png" alt=""></p>
<p>위 실행 화면에서는 여러 터미널에서 <code>order_manager</code>, <code>stock_server</code>, <code>payment_server</code>, <code>discount_server</code>, <code>order_client</code>, <code>log_monitor</code>가 동시에 실행된다. 주문이 들어오면 재고 확인, 할인 적용, 결제 승인, 로그 기록이 node별로 나뉘어 처리된다. 성공 주문은 <code>success=True</code>와 결제 승인 코드가 출력되고, 재고가 부족한 주문은 <code>rejected</code> 상태와 남은 재고가 출력된다. 이 이미지는 ROS2 service가 단순 예제 호출이 아니라 여러 node가 역할을 나누어 하나의 업무 흐름을 구성할 수 있음을 보여 준다.</p>
<h3 id="123-action-장기-작업-통신">1.2.3. Action: 장기 작업 통신</h3>
<p>Action은 시간이 오래 걸리는 목표 수행에 적합하다. Service는 요청을 보내고 응답을 기다리는 구조이지만, 로봇의 이동이나 작업 수행은 즉시 끝나지 않는다. 로봇 팔을 목표 위치로 이동시키거나, 모바일 로봇이 목적지까지 주행하거나, 물체를 집고 옮기는 작업은 진행 중 상태를 확인하고, 필요하면 취소할 수 있어야 한다.</p>
<p>Action은 goal, feedback, result 구조를 가진다. Client는 goal을 보내고, server는 수행 중 feedback을 보내며, 작업이 끝나면 result를 반환한다. 이 구조는 로봇 motion planning이나 navigation처럼 시간이 걸리는 작업에 적합하다.</p>
<p>ROS2의 Action 개념은 MoveIt과도 연결된다. MoveIt에서 trajectory execution은 단순한 함수 호출이 아니라 목표 trajectory를 실행하고 상태를 추적하는 장기 작업으로 볼 수 있다. 따라서 Action은 로봇의 “명령을 보내고 끝”이 아니라 “목표를 주고 수행 과정을 관리”하는 방식으로 이해해야 한다.</p>
<h3 id="124-topic-service-action-통신-방식-비교와-핵심-코드">1.2.4. Topic, Service, Action: 통신 방식 비교와 핵심 코드</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>ROS2 통신 구조에서 가장 중요한 단위는 node, topic, service, action이다. 이들은 모두 노드 사이의 연결을 만든다는 공통점이 있지만, 다루는 데이터의 성격이 다르다. 이 차이를 정확히 이해해야 로봇 시스템을 설계할 수 있다.</p>
<p>Node는 ROS2 시스템의 기본 실행 단위다. 하나의 node는 보통 하나의 책임을 가진다. 센서 값을 읽는 node, 모터 명령을 보내는 node, 카메라 이미지를 처리하는 node, 물체 검출 결과를 publish하는 node처럼 역할을 분리한다. Node를 작게 나누면 재사용과 디버깅이 쉬워진다.</p>
<ul>
<li><strong>Topic: 계속 흐르는 상태와 이벤트</strong></li>
</ul>
<p>Topic은 지속적으로 흐르는 데이터에 적합한 통신 방식이다. Publisher는 topic에 message를 발행하고, subscriber는 해당 topic을 구독해 message를 받는다. 센서 데이터, 카메라 이미지, 로봇 상태, joint state, object detection 결과처럼 계속 갱신되는 데이터는 topic으로 다루는 것이 자연스럽다.</p>
<p>Topic의 핵심은 비동기성이다. Publisher는 subscriber가 누구인지 직접 알 필요가 없고, subscriber도 publisher의 내부 구현을 알 필요가 없다. 둘은 topic name과 message type을 통해 느슨하게 연결된다.</p>
<ul>
<li><strong>Service: 명확한 요청과 응답</strong></li>
</ul>
<p>Service는 명확한 요청과 응답이 필요한 작업에 적합하다. Client가 request를 보내면 server가 response를 돌려준다. 재고 확인, 설정 값 조회, 특정 계산 요청, 간단한 상태 확인처럼 “질문을 보내고 답을 받는” 구조라면 service가 어울린다.</p>
<p>Service는 함수 호출과 비슷하게 느껴질 수 있지만 실제로는 노드 사이의 네트워크 통신이다. 따라서 service server가 준비되어 있는지 확인해야 하고, 응답 지연이나 실패 가능성도 고려해야 한다.</p>
<p>Service를 구성할 때는 먼저 <code>.srv</code> interface를 설계해야 한다. <code>.srv</code> 파일은 <code>---</code>를 기준으로 위쪽 request와 아래쪽 response를 나눈다. Request에는 client가 server에게 처리해 달라고 보낼 입력 값을 넣고, response에는 server가 처리 후 돌려줄 결과 값을 넣는다.</p>
<p>예를 들어 주문 처리 흐름에서는 <code>PlaceOrder</code> service가 주문 요청을 받는 외부 interface가 된다. Request에는 <code>order_id</code>, <code>item_id</code>, <code>quantity</code>, <code>amount</code>, <code>currency</code>처럼 주문을 처리하는 데 필요한 값이 들어간다. Response에는 <code>success</code>, <code>status</code>, <code>detail</code>, <code>remaining_stock</code>, <code>payment_auth_code</code>처럼 주문 결과를 해석하는 데 필요한 값이 들어간다.</p>
<p>이 interface를 기준으로 server와 client가 분리된다. <code>order_client</code>는 <code>PlaceOrder.Request</code> 객체를 만들어 값을 채우고 service를 호출한다. <code>order_manager</code>는 <code>PlaceOrder</code> service server를 열어 request를 받은 뒤, 내부에서 <code>CheckStock</code>, <code>AuthorizePayment</code>, <code>DiscountApply</code> 같은 다른 service client를 호출해 결과를 조합한다. 마지막으로 <code>PlaceOrder.Response</code>에 성공 여부와 상세 정보를 채워 client에게 돌려준다.</p>
<p>따라서 service 실습의 핵심은 server/client 코드를 각각 실행하는 것이 아니라, request/response interface가 여러 node의 책임을 어떻게 연결하는지 이해하는 것이다. 재고 확인은 stock server가 담당하고, 결제 승인은 payment server가 담당하며, 주문 manager는 이 결과를 조합해 하나의 주문 처리 결과로 만든다.</p>
<ul>
<li><strong>Action: 진행률과 취소가 필요한 목표 수행</strong></li>
</ul>
<p>Action은 시간이 오래 걸리는 목표 수행에 적합하다. 로봇 팔을 특정 위치로 이동시키거나, 모바일 로봇을 목표 지점까지 이동시키는 작업은 즉시 끝나지 않는다. 이런 작업은 목표를 보내고, 수행 중 feedback을 받고, 최종 result를 받으며, 필요하면 cancel할 수 있어야 한다.</p>
<p>Action은 service처럼 목표를 요청하지만, topic처럼 중간 상태를 계속 받을 수 있다는 점에서 장기 작업에 적합하다.</p>
<p><strong>통신 방식 실습 정리</strong></p>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>서비스 서버와 서비스 클라이언트가 함께 등장하는 구조는 ROS2의 요청/응답 흐름을 이해하는 데 좋다. 주문 관리 node가 주문 요청을 받으면 재고 확인 service와 결제 승인 service를 차례로 호출할 수 있다. 이 구조에서 하나의 node는 service server이면서 동시에 다른 service의 client가 된다.</p>
<p>이 실습을 통해 ROS2 통신 방식이 단순 문법 문제가 아니라 시스템 책임 분리의 문제라는 점을 이해할 수 있다. 어떤 데이터가 계속 흘러야 하는지, 어떤 기능은 요청/응답으로 처리해야 하는지, 어떤 목표는 action으로 관리해야 하는지 판단해야 한다.</p>
<p><strong>Topic 코드: publisher와 subscriber가 같은 topic 계약으로 만나는 코드</strong></p>
<p><code>my_pubsub/my_pub.py</code>의 핵심은 publisher 생성, timer 등록, 메시지 발행이다.</p>
<pre><code class="language-python">self.publisher_ = self.create_publisher(String, &#39;topic&#39;, 10)
self.timer = self.create_timer(timer_period, self.timer_callback)

msg = String()
msg.data = &#39;Hello World: %d&#39; % self.i
self.publisher_.publish(msg)</code></pre>
<p>여기서 <code>String</code>은 message type, <code>&#39;topic&#39;</code>은 통신 이름, <code>10</code>은 QoS queue depth다. Publisher가 상대 node를 직접 호출하지 않는다는 점이 중요하다. 이 node는 “누가 받을지”가 아니라 “어떤 topic에 어떤 type의 메시지를 흘릴지”만 정한다. 그래서 publisher와 subscriber는 서로의 파일명, class명, 내부 구현을 몰라도 topic 이름과 message type만 같으면 연결된다.</p>
<p><code>my_pubsub/my_sub.py</code>는 같은 topic과 같은 message type을 기준으로 callback을 연결한다.</p>
<pre><code class="language-python">self.subscription = self.create_subscription(
    String,
    &#39;topic&#39;,
    self.listener_callback,
    10
)

def listener_callback(self, msg):
    self.get_logger().info(&#39;I heard: &quot;%s&quot;&#39; % msg.data)</code></pre>
<p>Subscriber의 본질은 값을 “가져오는” 것이 아니라 도착한 message를 callback으로 처리하는 것이다. 그래서 topic은 sensor stream, robot state, log, detection 결과처럼 지속적으로 흘러가고 여러 node가 동시에 관찰해도 되는 데이터에 맞다.</p>
<p><code>smart_shop_nodes/log_monitor.py</code>는 topic이 사건 기록에도 쓰인다는 점을 보여 준다.</p>
<pre><code class="language-python">self.subscription = self.create_subscription(
    OrderLog,
    &#39;order_log&#39;,
    self.listener_callback,
    10
)

if msg.success:
    self.success_count += 1
else:
    self.failed_count += 1</code></pre>
<p>주문 처리는 service로 요청/응답을 끝내지만, 처리 결과는 <code>OrderLog</code> message로 <code>order_log</code> topic에 남는다. <code>log_monitor</code>는 주문을 요청한 client가 아니어도 같은 topic을 구독해 성공/실패 통계를 만들 수 있다. 따라서 topic은 “명령을 처리해 달라”보다 “상태 변화나 사건을 여러 node가 관찰하게 하라”에 가깝다.</p>
<p><strong>Service 코드: <code>.srv</code>가 request와 response 계약을 만드는 코드</strong></p>
<p>Service 실습에서 <code>.srv</code> 파일은 단순 보조 파일이 아니라 server와 client가 공유하는 함수 시그니처에 해당한다. 예를 들어 <code>PlaceOrder.srv</code>는 위쪽에 request, <code>---</code> 아래쪽에 response를 둔다.</p>
<pre><code class="language-srv">string order_id
string item_id
int32 quantity
float64 amount
string currency
---
bool success
string status
string detail
int32 remaining_stock
string payment_auth_code</code></pre>
<p><code>---</code> 위는 client가 server에게 넘겨야 하는 입력이다. <code>order_id</code>, <code>item_id</code>, <code>quantity</code>, <code>amount</code>, <code>currency</code>가 없으면 주문 처리에 필요한 판단을 할 수 없다. <code>---</code> 아래는 server가 처리 후 돌려줘야 하는 결과다. <code>success</code>만 있으면 왜 실패했는지 알 수 없으므로 <code>status</code>, <code>detail</code>, <code>remaining_stock</code>, <code>payment_auth_code</code>처럼 다음 판단에 필요한 정보를 함께 둔다.</p>
<p><code>order_manager.py</code>는 이 interface를 server로 열면서 동시에 다른 service들의 client가 된다.</p>
<pre><code class="language-python">self.srv = self.create_service(
    PlaceOrder,
    &#39;place_order&#39;,
    self.cb_place_order,
    callback_group=self.cb_group
)

self.stock_cli = self.create_client(CheckStock, &#39;check_stock&#39;, callback_group=self.cb_group)
self.pay_cli = self.create_client(AuthorizePayment, &#39;authorize_payment&#39;, callback_group=self.cb_group)
self.disc_cli = self.create_client(DiscountApply, &#39;discount_apply&#39;, callback_group=self.cb_group)</code></pre>
<p>이 구조에서 <code>order_manager</code>는 외부에는 <code>place_order</code> 기능을 제공하는 server지만, 내부 처리에는 재고, 할인, 결제 service를 호출하는 client다. 그래서 service는 “한 node가 한 역할만 한다”가 아니라, 각 node가 자신의 책임을 service로 공개하고 필요한 기능을 다른 service에 요청하는 구조다.</p>
<p>처리 흐름은 request를 받아 내부 service request로 바꾸고, 각 response를 근거로 최종 response를 채우는 방식이다.</p>
<pre><code class="language-python">stock_res = self.stock_cli.call(stock_req)
disc_res = self.disc_cli.call(disc_req)
pay_res = self.pay_cli.call(pay_req)

response.success = True
response.status = &#39;success&#39;
response.remaining_stock = stock_res.remaining
response.payment_auth_code = pay_res.auth_code</code></pre>
<p>따라서 workspace, package, interface의 역할도 함께 정리된다. Workspace는 여러 package를 같은 빌드 환경에서 묶는 단위다. Interface package는 <code>.srv</code>와 <code>.msg</code>를 두고 빌드 과정에서 Python/C++에서 import 가능한 타입을 생성한다. Node package는 생성된 타입을 사용해 실제 server, client, publisher, subscriber 동작을 구현한다. Interface와 구현을 분리해야 service 계약은 유지하면서 node 내부 로직을 바꿀 수 있다.</p>
<p><strong>Action 코드: goal, feedback, result가 나뉘는 코드</strong></p>
<p><code>my_action_interfaces/action/PatrolTest.action</code>은 action이 세 구역으로 나뉜다는 점을 코드 자체로 보여 준다.</p>
<pre><code class="language-action">geometry_msgs/Pose2D[] waypoints
float64 tolerance
---
bool success
string message
---
int32 current_index
float64 distance_remaining</code></pre>
<p>첫 번째 구역은 goal이다. Patrol에서는 여러 waypoint와 허용 오차가 목표다. 두 번째 구역은 result다. 모든 waypoint 수행이 끝난 뒤 성공 여부와 메시지를 돌려준다. 세 번째 구역은 feedback이다. 실행 도중 현재 waypoint index와 남은 거리를 계속 알려 준다.</p>
<p><code>patrol_action_server.py</code>의 핵심은 goal을 받은 뒤 즉시 끝내지 않고 실행 상태를 유지한다는 점이다.</p>
<pre><code class="language-python">feedback_msg.current_index = self.current_idx
feedback_msg.distance_remaining = dist
goal_handle.publish_feedback(feedback_msg)

if self.current_idx &gt;= len(self.waypoints):
    goal_handle.succeed()
    result.success = True
    return result</code></pre>
<p>Service라면 request를 받고 response를 한 번 돌려주면 끝난다. 하지만 patrol, navigation, robot arm trajectory, pick-and-place sequence는 시간이 걸리는 목표 수행이다. 실행 중 feedback을 보고, 필요하면 cancel하며, 끝났을 때 result를 받아야 하므로 action이 필요하다.</p>
<p><strong>Spin과 executor 코드: callback을 실제로 실행하는 부분</strong></p>
<p>ROS2 node에서 publisher, subscriber, service, action을 생성하는 것만으로 callback이 저절로 실행되지는 않는다. Callback을 처리하려면 node를 executor에 올리고 spin해야 한다. <code>order_manager.py</code>는 service callback 안에서 다른 service를 동기 호출하므로 <code>ReentrantCallbackGroup</code>과 <code>MultiThreadedExecutor</code>를 함께 사용한다.</p>
<pre><code class="language-python">self.cb_group = ReentrantCallbackGroup()

self.srv = self.create_service(
    PlaceOrder,
    &#39;place_order&#39;,
    self.cb_place_order,
    callback_group=self.cb_group
)

self.stock_cli = self.create_client(
    CheckStock,
    &#39;check_stock&#39;,
    callback_group=self.cb_group
)</code></pre>
<pre><code class="language-python">executor = MultiThreadedExecutor(num_threads=4)
executor.add_node(node)

try:
    executor.spin()
except KeyboardInterrupt:
    pass
finally:
    node.destroy_node()
    rclpy.shutdown()</code></pre>
<p>여기서 <code>create_service</code>와 <code>create_client</code>는 통신 endpoint를 만드는 부분이고, <code>executor.spin()</code>은 실제 callback을 계속 받아 실행하는 event loop다. Service callback 안에서 다시 service를 호출하는 구조는 한 callback이 기다리는 동안 다른 callback도 처리될 수 있어야 하므로 multi-threaded executor가 필요하다. 즉 spin은 보조 코드가 아니라 ROS2 통신이 실제로 살아 움직이게 하는 실행 조건이다.</p>
<p><strong>Service 대기와 fallback 코드: dependency가 없을 때 안전하게 응답하는 부분</strong></p>
<p>Service client는 server가 떠 있다는 가정만으로 호출하면 안 된다. <code>order_manager.py</code>는 내부 dependency인 <code>check_stock</code>, <code>authorize_payment</code> service가 준비되지 않았을 때 기다려 보고, 없으면 실패 response를 명시적으로 채운다.</p>
<pre><code class="language-python">def wait_service_or_fail(self, client, name, timeout_sec=3.0):
    if not client.wait_for_service(timeout_sec=timeout_sec):
        self.get_logger().error(f&quot;Service not available: {name}&quot;)
        return False
    return True</code></pre>
<pre><code class="language-python">if not self.wait_service_or_fail(self.stock_cli, &#39;check_stock&#39;):
    response.success = False
    response.status = &quot;dependency_unavailable&quot;
    response.detail = &quot;check_stock not available&quot;
    response.remaining_stock = 0
    response.payment_auth_code = &quot;&quot;
    return response</code></pre>
<p>이 fallback은 예외가 나면 프로그램을 멈추는 방식이 아니라, service 계약에 맞는 실패 응답을 돌려주는 방식이다. Client 입장에서는 응답이 끊기지 않고 <code>success=False</code>, <code>status=&quot;dependency_unavailable&quot;</code>를 통해 실패 원인을 해석할 수 있다. 그래서 service interface에는 성공 여부뿐 아니라 상태 문자열과 상세 이유를 넣는 것이 중요하다.</p>
<p><code>test_svc/my_client.py</code>는 async service client에서 service 준비 대기와 future spin을 보여 준다.</p>
<pre><code class="language-python">self.cli = self.create_client(AddTwoInts, &#39;add_two_ints&#39;)
while not self.cli.wait_for_service(timeout_sec=1.0):
    self.get_logger().info(&#39;service not available, waiting again...&#39;)</code></pre>
<pre><code class="language-python">future = minimal_client.send_request(int(sys.argv[1]), int(sys.argv[2]))
rclpy.spin_until_future_complete(minimal_client, future)
response = future.result()</code></pre>
<p><code>call_async()</code>는 요청을 보내고 즉시 future를 돌려준다. 결과가 올 때까지 node가 callback 처리를 해야 하므로 <code>spin_until_future_complete()</code>가 필요하다. 이 코드는 service가 단순 함수 호출처럼 보이더라도 실제로는 ROS graph 안에서 request와 response가 오가고, executor가 그 응답을 처리해야 한다는 점을 보여 준다.</p>
<p><strong>Action server 코드: pub/sub/timer/action이 한 node 안에서 결합되는 부분</strong></p>
<p><code>patrol_action_server.py</code>는 action이 단독 통신이 아니라 topic, timer, callback과 함께 동작한다는 점을 잘 보여 준다.</p>
<pre><code class="language-python">self.cmd_pub = self.create_publisher(Twist, &#39;/turtle1/cmd_vel&#39;, 10)
self.create_subscription(Pose, &#39;/turtle1/pose&#39;, self.pose_cb, 10)
self.server = ActionServer(
    self,
    PatrolTest,
    &#39;patrol&#39;,
    execute_callback=self.execute_callback,
    goal_callback=self.goal_callback,
    handle_accepted_callback=self.handle_accepted_callback,
    cancel_callback=self.cancel_callback,
    callback_group=self.cb
)

self.timer = self.create_timer(0.05, self.timer_cb, callback_group=self.cb)</code></pre>
<p>Action server는 <code>patrol</code> goal을 받고, pose는 <code>/turtle1/pose</code> topic subscription으로 계속 갱신하며, 실제 속도 명령은 <code>/turtle1/cmd_vel</code> topic으로 publish한다. <code>timer_cb()</code>는 주기적으로 현재 pose와 goal waypoint를 비교해 feedback과 제어 명령을 만든다.</p>
<pre><code class="language-python">if self.goal_handle.is_cancel_requested:
    self.stop()
    self.goal_handle.canceled()
    self.reset()
    return

fb = PatrolTest.Feedback()
fb.current_index = self.idx
fb.remaining_distance = dist
self.goal_handle.publish_feedback(fb)

self.cmd_pub.publish(cmd)</code></pre>
<p>Cancel 요청이 오면 로봇을 멈추고 action 상태를 canceled로 바꾼다. 실행 중에는 feedback을 publish해 client가 진행 상황을 볼 수 있게 하고, 동시에 <code>Twist</code> 명령을 publish해 turtlesim을 움직인다. 따라서 action은 “긴 service”가 아니라 goal 관리, feedback, cancel, 내부 topic 제어가 결합된 실행 구조다.</p>
<pre><code class="language-python">executor = MultiThreadedExecutor()
executor.add_node(node)
executor.spin()</code></pre>
<p>이 action server도 executor가 spin해야 goal callback, cancel callback, timer callback, subscription callback이 처리된다. 특히 timer 기반 action은 spin이 멈추면 feedback도, 제어 명령 publish도 멈춘다.</p>
<p><strong>통신 파이프라인 코드: 어디서 보내고 어디서 받는가</strong></p>
<p>ROS2 실습 코드를 읽을 때는 <code>publish()</code>나 <code>callback()</code> 한 줄만 보지 말고, 데이터가 어떤 방향으로 흐르는지 따라가야 한다. 가장 단순한 topic 실습의 파이프라인은 <code>my_pub.py -&gt; topic -&gt; my_sub.py</code>다.</p>
<pre><code class="language-python">self.publisher_ = self.create_publisher(String, &#39;topic&#39;, 10)
self.timer = self.create_timer(timer_period, self.timer_callback)

msg = String()
msg.data = &#39;Hello World: %d&#39; % self.i
self.publisher_.publish(msg)</code></pre>
<pre><code class="language-python">self.subscription = self.create_subscription(
    String,
    &#39;topic&#39;,
    self.listener_callback,
    10
)

def listener_callback(self, msg):
    self.get_logger().info(&#39;I heard: &quot;%s&quot;&#39; % msg.data)</code></pre>
<p>여기서 <code>my_pub.py</code>는 timer callback에서 <code>String</code> message를 만들어 <code>topic</code>으로 날린다. <code>my_sub.py</code>는 같은 topic 이름과 같은 message type을 기준으로 message를 받고 <code>listener_callback()</code>에서 처리한다. Cmd에서는 보통 publisher node와 subscriber node를 각각 실행한 뒤, 필요하면 <code>ros2 topic list</code>, <code>ros2 topic echo /topic</code>으로 중간에 흐르는 message를 확인한다. 즉 topic은 sender와 receiver가 서로를 직접 부르지 않고, ROS graph의 topic 이름을 통해 만나는 구조다.</p>
<p>Service 실습의 파이프라인은 <code>client -&gt; place_order service -&gt; order_manager -&gt; 내부 service들 -&gt; 최종 response</code>다. <code>order_manager.py</code>는 외부에서 <code>place_order</code> 요청을 받는 server이면서, 내부적으로는 재고와 결제 service를 호출하는 client다.</p>
<pre><code class="language-python">self.srv = self.create_service(
    PlaceOrder,
    &#39;place_order&#39;,
    self.cb_place_order,
    callback_group=self.cb_group
)

self.stock_cli = self.create_client(CheckStock, &#39;check_stock&#39;, callback_group=self.cb_group)
self.pay_cli = self.create_client(AuthorizePayment, &#39;authorize_payment&#39;, callback_group=self.cb_group)</code></pre>
<pre><code class="language-python">stock_res = self.stock_cli.call(stock_req)
pay_res = self.pay_cli.call(pay_req)

response.success = True
response.status = &quot;success&quot;
response.detail = &quot;order accepted&quot;
response.remaining_stock = stock_res.remaining
response.payment_auth_code = pay_res.auth_code</code></pre>
<p>이 흐름에서 <code>place_order</code>로 들어온 request는 <code>cb_place_order()</code> 안에서 <code>CheckStock.Request</code>, <code>AuthorizePayment.Request</code>로 다시 바뀌어 다른 service로 날아간다. 각 service의 response가 돌아오면 <code>order_manager</code>가 최종 <code>PlaceOrder.Response</code>를 채운다. Cmd에서는 server node들이 먼저 떠 있어야 하고, client가 service call을 보낸 뒤 response를 확인한다. 중간 service가 없으면 앞에서 본 <code>wait_for_service()</code>와 fallback response가 작동한다.</p>
<p>Action 실습의 파이프라인은 <code>action client -&gt; patrol goal -&gt; action server -&gt; /turtle1/cmd_vel -&gt; turtlesim</code>, 그리고 반대 방향으로 <code>/turtle1/pose -&gt; action server -&gt; feedback -&gt; action client</code>가 동시에 흐른다.</p>
<pre><code class="language-python">goal_msg = PatrolTest.Goal()
goal_msg.waypoints = self.generate_random_waypoints(count=100)
goal_msg.tolerance = 0.3

self._client.wait_for_server()
send_future = self._client.send_goal_async(
    goal_msg,
    feedback_callback=self.feedback_callback
)</code></pre>
<pre><code class="language-python">def feedback_callback(self, feedback_msg):
    fb = feedback_msg.feedback
    self.get_logger().info(
        f&#39;Feedback: waypoint={fb.current_index}, &#39;
        f&#39;remaining={fb.remaining_distance:.2f}&#39;
    )</code></pre>
<p>Client는 waypoint 목록을 goal로 보내고, server는 pose topic으로 현재 위치를 받아 다음 속도 명령을 계산한다. Server가 <code>/turtle1/cmd_vel</code>로 <code>Twist</code>를 publish하면 turtlesim이 움직이고, turtlesim은 다시 <code>/turtle1/pose</code>를 publish한다. Server는 pose를 보고 남은 거리를 feedback으로 client에게 보내며, Enter 입력 같은 조건이 들어오면 client가 cancel request를 보낸다. 이 구조 때문에 action은 단순한 “요청 후 응답”이 아니라 목표, 상태 관찰, 제어 명령, feedback, cancel이 동시에 묶인 파이프라인이다.</p>
<p><strong>Cmd에서 파이프라인을 확인하는 법</strong></p>
<p>실습을 실행할 때 cmd에서는 “node를 실행한다”와 “ROS graph 안에서 흐름을 관찰한다”를 나누어 봐야 한다. <code>setup.py</code>의 console script를 보면 <code>my_pubsub</code> package는 <code>talker</code>, <code>listener</code> 실행 파일을 만든다.</p>
<pre><code class="language-python">entry_points={
    &#39;console_scripts&#39;: [
        &#39;talker = my_pubsub.my_pub:main&#39;,
        &#39;listener = my_pubsub.my_sub:main&#39;,
    ],
}</code></pre>
<p>따라서 build와 source가 끝난 뒤에는 다음처럼 두 node를 각각 실행하고, 다른 터미널에서 topic을 확인할 수 있다.</p>
<pre><code class="language-bash">ros2 run my_pubsub talker
ros2 run my_pubsub listener
ros2 topic list
ros2 topic echo /topic</code></pre>
<p>Service 실습의 <code>setup.py</code>는 <code>service</code>, <code>client</code> 실행 파일을 만든다.</p>
<pre><code class="language-python">entry_points={
    &#39;console_scripts&#39;: [
        &#39;service = my_svc.my_service:main&#39;,
        &#39;client = my_svc.my_client:main&#39;,
    ],
}</code></pre>
<p>이때 실행 순서는 server를 먼저 띄우고 client를 실행하는 방식이다. <code>ros2 service list</code>로 <code>add_two_ints</code>가 보이는지 확인하고, client를 실행하면 <code>call_async()</code>로 request가 날아가고 <code>spin_until_future_complete()</code> 이후 response가 출력된다.</p>
<pre><code class="language-bash">ros2 run my_svc service
ros2 service list
ros2 run my_svc client 2 3</code></pre>
<p>Action 실습의 <code>my_patrol_server</code> package는 action server와 client를 따로 실행하게 되어 있다.</p>
<pre><code class="language-python">entry_points={
    &#39;console_scripts&#39;: [
        &#39;patrol_action_server = my_patrol_server.patrol_action_server:main&#39;,
        &#39;patrol_action_client = my_patrol_server.patrol_action_client:main&#39;,
    ],
}</code></pre>
<p>Cmd에서는 turtlesim, patrol server, patrol client를 함께 띄운 뒤 action과 topic을 동시에 확인한다. <code>/turtle1/cmd_vel</code>은 server가 turtlesim으로 날리는 제어 명령이고, <code>/turtle1/pose</code>는 turtlesim이 server에게 돌려주는 현재 상태다.</p>
<pre><code class="language-bash">ros2 run turtlesim turtlesim_node
ros2 run my_patrol_server patrol_action_server
ros2 run my_patrol_server patrol_action_client
ros2 topic echo /turtle1/cmd_vel
ros2 topic echo /turtle1/pose
ros2 action list</code></pre>
<p>이렇게 실행하면 코드 안의 <code>create_publisher</code>, <code>create_subscription</code>, <code>ActionClient</code>, <code>ActionServer</code>, <code>spin()</code>이 cmd에서 보이는 ROS graph와 대응된다. 즉 cmd는 단순 실행 창이 아니라, 코드 파이프라인이 실제 ROS 통신으로 연결되었는지 검증하는 관찰 도구다.</p>
<ul>
<li><strong>같은 시스템 안에서 세 통신이 함께 쓰이는 이유</strong></li>
</ul>
<p>하나의 로봇 시스템은 보통 topic, service, action 중 하나만 쓰지 않는다. 센서와 상태는 topic으로 계속 흐르고, 설정 조회나 단발 판단은 service로 처리되며, 시간이 걸리는 목표 수행은 action으로 관리된다. Smart shop 예제에서는 주문 요청은 service이고 주문 로그는 topic이다. Patrol 예제에서는 목표 waypoint 수행이 action이고, 내부 제어 명령은 topic이다. 통신 방식을 고르는 기준은 “데이터가 계속 흐르는가, 응답이 필요한가, 진행 중 상태와 취소가 필요한가”이다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Topic은 지속 데이터, Service는 요청과 응답, Action은 시간이 걸리는 목표 수행을 위한 통신 방식이다.</p>
<h2 id="13-launch와-parameter">1.3. Launch와 Parameter</h2>
<h3 id="131-launch-실행-구성">1.3.1. Launch: 실행 구성</h3>
<p>Launch는 여러 node와 설정을 한 번에 실행하기 위한 구성 파일이다. ROS2 시스템이 커지면 매번 터미널에서 node를 하나씩 실행하기 어렵다. 어떤 node를 실행할지, 어떤 parameter를 넣을지, topic 이름을 remap할지, namespace를 어떻게 둘지, RViz나 Gazebo를 함께 실행할지 등을 launch 파일에 묶는다.</p>
<p>Launch는 단순히 명령어를 줄이는 도구가 아니다. 로봇 시스템의 실행 구조를 기록하는 문서이기도 하다. Launch 파일을 보면 어떤 node들이 함께 동작하고, 어떤 설정으로 연결되는지 알 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/cd10ac1e-b8e0-422c-84e9-f98861503818/image.png" alt=""></p>
<p>위 이미지는 launch 파일로 여러 Turtlesim node를 실행하고, 배경색 parameter를 바꾸는 실습 화면이다. 오른쪽 코드에는 <code>generate_launch_description()</code>과 <code>TimerAction</code>, event handler가 보이고, 터미널에는 여러 node가 process로 시작되는 로그가 보인다. 이 이미지는 launch가 단순 실행 단축이 아니라 여러 node와 이벤트, parameter 변경을 하나의 실행 시나리오로 구성한다는 점을 보여 준다.</p>
<h3 id="132-parameter-실행-조건">1.3.2. Parameter: 실행 조건</h3>
<p>Parameter는 node의 동작을 코드 수정 없이 바꾸기 위한 설정 값이다. 로봇 속도 제한, 센서 주기, controller gain, threshold, 목표 위치, 색상 값, planning 옵션 같은 값은 코드 안에 박아두기보다 parameter로 분리하는 것이 좋다.</p>
<p>Parameter를 사용하면 같은 node를 여러 조건에서 반복 실험할 수 있다. 예를 들어 Turtlesim 배경색을 바꾸거나, 센서 publish 주기를 바꾸거나, controller 설정값을 바꾸는 일을 코드 수정 없이 할 수 있다. 이렇게 하면 알고리즘 코드는 그대로 두고 실행 조건만 바꿀 수 있어, 실험 결과를 비교할 때 어떤 조건이 달라졌는지 추적하기 쉽다.</p>
<h3 id="133-launch와-parameter-실습-코드와-실행-시나리오">1.3.3. Launch와 Parameter: 실습 코드와 실행 시나리오</h3>
<ul>
<li><strong>기본 개념</strong></li>
</ul>
<p>ROS2 시스템이 커지면 여러 node를 매번 터미널에서 하나씩 실행하는 방식은 한계에 부딪힌다. 실행해야 할 node가 많아지고, 각 node에 넘겨야 할 parameter와 remapping이 늘어나며, namespace와 실행 순서도 관리해야 한다. Launch는 이런 실행 조건을 하나의 파일로 묶어 재현 가능한 실행 구성을 만드는 도구다.</p>
<p>Parameter는 node의 동작을 코드 수정 없이 바꾸기 위한 설정 값이다. 로봇 속도 제한, 센서 publish 주기, controller gain, 목표 위치, file path, threshold 값, planning 옵션 등은 parameter로 분리할 수 있다.</p>
<ul>
<li><strong>Launch의 역할</strong></li>
</ul>
<p>Launch 파일은 단순히 긴 명령어를 줄여 주는 편의 기능이 아니다. 로봇 시스템에서 launch는 실험 조건을 정의하는 문서이기도 하다. 어떤 node를 실행할지, 어떤 parameter 파일을 적용할지, topic 이름을 어떻게 remap할지, RViz나 Gazebo를 함께 실행할지, namespace를 어떻게 나눌지가 모두 launch에 들어갈 수 있다.</p>
<p>따라서 launch 파일을 보면 로봇 시스템의 실행 구조를 읽을 수 있다. 이는 단순히 실행 자동화가 아니라, 여러 node가 하나의 시스템으로 묶이는 방식을 기록하는 일이다.</p>
<ul>
<li><strong>Launch를 어떻게 구성하는가</strong></li>
</ul>
<p>Launch 파일은 보통 <code>generate_launch_description()</code> 함수에서 실행할 action들을 반환하는 구조로 작성한다. 여기에는 <code>Node</code> 실행, 다른 launch 파일 포함, parameter 파일 전달, remapping, namespace 지정, 시간 지연 실행, event handler 등록 등이 들어갈 수 있다.</p>
<p>예를 들어 Turtlesim을 여러 개 실행하는 실습에서는 각각의 turtlesim node를 다른 이름이나 namespace로 실행해야 충돌이 나지 않는다. 같은 node executable을 실행하더라도 node name과 namespace를 다르게 두면 서로 다른 프로세스처럼 관리할 수 있다. 여기에 parameter를 함께 넘기면 각 node의 배경색이나 동작 조건도 다르게 설정할 수 있다.</p>
<p>Launch 구성을 읽을 때는 “무엇이 실행되는가”와 “어떤 이름으로 연결되는가”를 봐야 한다. ROS2 시스템에서는 node 이름, namespace, topic 이름이 통신 구조를 결정하기 때문이다. Launch에서 remapping을 사용하면 코드 안의 topic 이름은 그대로 두고 실행 시점에 연결 대상을 바꿀 수 있다.</p>
<ul>
<li><strong>Parameter의 역할</strong></li>
</ul>
<p>Parameter를 코드 안에 직접 넣으면 조건을 바꿀 때마다 코드를 수정해야 하고, 실험 재현성이 떨어진다. Parameter로 분리하면 같은 node를 여러 조건에서 반복 실행할 수 있다.</p>
<p>로봇 시스템에서는 같은 알고리즘이라도 parameter에 따라 완전히 다른 동작을 보일 수 있다. Controller gain이 달라지면 로봇 움직임이 달라지고, sensor frequency가 달라지면 perception pipeline의 지연이 달라질 수 있다.</p>
<ul>
<li><strong>Parameter를 어떻게 설계하는가</strong></li>
</ul>
<p>Parameter에는 node의 본질적 알고리즘보다 실행 조건에 가까운 값을 넣는다. 예를 들어 threshold, publish rate, frame name, file path, robot description path, controller gain, planning option, sensor resolution 같은 값이 parameter가 되기 좋다. 반대로 알고리즘의 흐름 자체를 바꾸는 복잡한 로직은 parameter로 숨기기보다 코드 구조로 명확히 드러내야 한다.</p>
<p>Parameter를 YAML 파일로 분리하면 실험 조건을 파일 단위로 관리할 수 있다. 같은 node를 <code>sim.yaml</code>, <code>real_robot.yaml</code>, <code>debug.yaml</code>처럼 다른 설정으로 실행할 수 있고, 어떤 실험에서 어떤 설정을 썼는지 나중에 추적할 수 있다.</p>
<p><strong>Launch와 Parameter 실습 정리</strong></p>
<ul>
<li><strong>실습에서 확인할 점</strong></li>
</ul>
<p>Launch와 Parameter를 함께 다루면서 코드와 실험 설정을 분리하는 감각을 얻는다. 실습에서 봐야 하는 것은 실행 결과만이 아니다. 어떤 node들이 동시에 실행되는지, parameter가 어디서 들어오는지, topic 이름이 바뀌는지, node namespace가 나뉘는지 확인해야 한다.</p>
<p>실습에서 Turtlesim 배경색이나 실행 node 수가 launch와 parameter에 의해 바뀌었다면, 그 결과는 단순 화면 변화가 아니다. 같은 executable이라도 실행 구성에 따라 서로 다른 시스템이 만들어진다는 뜻이다. 이 원리를 Gazebo, RViz, MoveIt 실행으로 확장하면 복잡한 로봇 시스템도 하나의 launch entry point로 재현할 수 있다.</p>
<ul>
<li><strong>Launch는 실행 순서를 문서화한다</strong></li>
</ul>
<p><code>launch_ws/src/substitutions_py/launch/event_handlers_launch.py</code>는 launch가 여러 node를 동시에 켜는 정도에서 끝나지 않는다는 점을 보여 준다. <code>DeclareLaunchArgument</code>로 <code>turtlesim_ns</code>, <code>use_provided_red</code>, <code>new_background_r</code> 같은 실행 인자를 선언하고, <code>LaunchConfiguration</code>으로 실행 시점의 값을 읽는다. 이 값들은 node namespace나 parameter 변경 명령에 들어간다.</p>
<p>이 파일에서 <code>OnProcessStart</code>는 turtlesim node가 시작된 뒤 <code>TimerAction</code>으로 잠시 기다렸다가 <code>/spawn</code> service call을 실행한다. <code>OnExecutionComplete</code>는 spawn 명령이 끝난 뒤 배경색 parameter를 바꾸는 명령을 실행한다. <code>OnProcessExit</code>는 turtlesim 창이 닫히면 전체 launch를 shutdown한다. 따라서 launch는 “명령어 자동 실행”이 아니라 node 생명주기와 후속 동작을 연결하는 실행 시나리오다.</p>
<ul>
<li><strong>Substitution은 실행 시점 값을 끼워 넣는 장치다</strong></li>
</ul>
<p><code>main_launch.py</code>는 <code>IncludeLaunchDescription</code>으로 다른 launch 파일을 포함하고, <code>PathJoinSubstitution</code>, <code>FindPackageShare</code>, <code>TextSubstitution</code>을 사용해 package share 경로와 인자 값을 조립한다. 이 구조는 launch 파일 내부에 절대 경로를 박아 두지 않고, package가 설치된 위치를 ROS2가 찾게 만든다.</p>
<p>Substitution이 필요한 이유는 launch 파일이 작성 시점과 실행 시점의 정보를 모두 다루기 때문이다. package share 경로, 환경 변수, 실행 인자, node namespace는 실행 환경에 따라 달라질 수 있다. 이를 문자열로 고정하면 다른 PC나 다른 workspace에서 깨질 가능성이 커진다.</p>
<ul>
<li><strong>Multi Turtle 예제에서 namespace가 필요한 이유</strong></li>
</ul>
<p><code>multi_turtle_ws/src/multi_turtle_launch/launch/multi_turtle_launch.py</code>는 같은 <code>turtlesim_node</code> executable을 두 번 실행하면서 namespace를 <code>turtle_a</code>, <code>turtle_b</code>로 나눈다. 같은 executable이라도 namespace가 다르면 <code>/turtle_a/sim</code>, <code>/turtle_b/sim</code>처럼 서로 다른 node와 topic/service 공간을 만들 수 있다.</p>
<p>이 실습의 핵심은 “turtlesim 두 개가 뜬다”가 아니다. 같은 코드가 실행 구성에 따라 독립된 시스템 구성 요소가 될 수 있다는 점이다. 실제 로봇에서는 같은 카메라 driver를 front camera와 wrist camera에 각각 띄우거나, 같은 controller node를 다른 robot namespace 아래에서 실행할 때 이 원리가 필요하다.</p>
<ul>
<li><strong>Parameter는 코드가 아니라 실험 조건을 바꾼다</strong></li>
</ul>
<p><code>multi_turtle_launch.py</code>와 <code>speed_launch.py</code>에서는 launch argument와 parameter 변경 명령이 함께 등장한다. 예를 들어 background color를 parameter로 바꾸면 turtlesim node 코드를 수정하지 않고 실행 조건만 바꾼다. <code>speed_controller.py</code>처럼 별도 node를 함께 실행하면 사용자가 보는 화면 변화와 topic command 흐름이 launch 구성으로 묶인다.</p>
<p>Parameter를 이렇게 분리하는 이유는 같은 알고리즘을 여러 조건에서 재사용하기 위해서다. 로봇에서는 속도 제한, publish 주기, controller gain, planning time, sensor threshold, frame name 같은 값을 코드에 직접 박아 두면 실험마다 코드를 고쳐야 한다. Parameter로 빼면 launch나 YAML만 바꿔 같은 node를 다른 환경에서 실행할 수 있다.</p>
<ul>
<li><strong>실습 코드에서 확인해야 할 순서</strong></li>
</ul>
<p>Launch 파일을 읽을 때는 먼저 어떤 <code>Node</code>가 실행되는지 보고, 다음으로 namespace와 name이 어떻게 붙는지 본다. 그다음 parameter가 어디서 들어오는지, <code>ExecuteProcess</code>로 외부 명령을 호출하는지, <code>RegisterEventHandler</code>가 어떤 event에 어떤 후속 action을 연결하는지 확인한다. 이렇게 읽어야 launch가 시스템 실행 구조를 설명하는 문서처럼 보인다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>Launch는 여러 node와 실행 조건을 묶고, Parameter는 같은 코드의 동작을 설정으로 바꾸게 해 준다.</p>
<h2 id="14-workspace-package-interface">1.4. Workspace, Package, Interface</h2>
<p>ROS2 workspace는 여러 package를 한 번에 빌드하고 실행 환경으로 묶는 최상위 작업 공간이다. 실습에서 보인 <code>svc_ws</code> 같은 구조는 보통 <code>src</code> 폴더 아래에 package들이 들어가고, <code>colcon build</code>를 실행하면 <code>build</code>, <code>install</code>, <code>log</code> 폴더가 생성된다. 이후 <code>source install/local_setup.bash</code>를 실행해야 현재 터미널이 방금 빌드한 package와 interface를 인식한다.</p>
<p>Package는 역할 단위로 나누어 구성한다. Service 실습에서는 interface를 정의하는 package와 실제 node를 구현하는 package를 분리하는 구조가 확인된다. 예를 들어 <code>smart_shop_interfaces</code>는 <code>.srv</code> 파일을 담는 interface package이고, <code>smart_shop_nodes</code>는 <code>stock_server</code>, <code>payment_server</code>, <code>discount_server</code>, <code>order_manager</code>, <code>order_client</code>, <code>log_monitor</code> 같은 실행 node를 담는 Python package다.</p>
<p>이렇게 package를 분리하는 이유는 interface와 구현을 독립시키기 위해서다. <code>.srv</code> 파일은 server와 client가 공유하는 약속이다. Node 구현이 바뀌어도 request와 response 구조가 유지되면 다른 node는 같은 방식으로 통신할 수 있다. 반대로 <code>.srv</code> 구조가 바뀌면 server와 client 모두 새 interface에 맞게 다시 빌드하고 수정해야 한다.</p>
<h3 id="141-srv-파일-구성">1.4.1. <code>.srv</code> 파일 구성</h3>
<p><code>.srv</code> 파일은 service 통신의 request와 response 형식을 정의한다. 파일 안에서는 <code>---</code> 위쪽이 request, 아래쪽이 response다. 예를 들어 재고 확인 service라면 request에는 <code>item_id</code>, <code>quantity</code> 같은 필드가 들어가고, response에는 <code>available</code>, <code>remaining</code>, <code>reason</code> 같은 필드가 들어갈 수 있다.</p>
<p>주문 처리 service라면 request에는 주문을 식별하고 처리하는 데 필요한 값이 들어가야 한다. 예를 들어 <code>order_id</code>, <code>item_id</code>, <code>quantity</code>, <code>amount</code>, <code>currency</code>가 request에 들어갈 수 있다. Response에는 주문 처리 결과를 client가 해석할 수 있도록 <code>success</code>, <code>status</code>, <code>detail</code>, <code>remaining_stock</code>, <code>payment_auth_code</code> 같은 필드가 필요하다.</p>
<p>이 구조는 단순 데이터 나열이 아니라 node 사이의 계약이다. <code>order_client</code>는 request 필드에 값을 채워 <code>place_order</code> service를 호출하고, <code>order_manager</code>는 같은 <code>.srv</code> 정의를 기준으로 request를 읽어 처리한 뒤 response를 채운다. 이때 response의 <code>success</code>는 전체 처리 성공 여부, <code>status</code>는 <code>success</code>나 <code>rejected</code> 같은 상태, <code>detail</code>은 실패 이유나 할인 적용 결과, <code>remaining_stock</code>은 재고 처리 결과, <code>payment_auth_code</code>는 결제 승인 결과를 전달한다.</p>
<h3 id="142-service-package를-구성하는-방식">1.4.2. Service package를 구성하는 방식</h3>
<p>Service interface package는 보통 <code>srv</code> 폴더에 <code>.srv</code> 파일을 둔다. ROS2는 빌드 과정에서 이 <code>.srv</code> 파일을 언어별 message/service class로 생성한다. Python node에서는 생성된 interface를 import해서 <code>PlaceOrder.Request</code>, <code>PlaceOrder.Response</code>처럼 사용한다.</p>
<p>Node package는 service server와 client를 구현한다. <code>stock_server</code>는 <code>CheckStock</code> service server로 재고 가능 여부를 판단하고, <code>payment_server</code>는 <code>AuthorizePayment</code> service server로 결제 승인 여부를 만든다. <code>discount_server</code>는 할인율을 계산하는 service가 될 수 있다. <code>order_manager</code>는 <code>PlaceOrder</code> service server로 외부 주문을 받으면서 내부적으로 재고, 할인, 결제 service client를 호출한다. <code>order_client</code>는 사용자가 보낸 주문 요청을 <code>place_order</code> service로 보내고 response를 출력한다.</p>
<p>이 구조에서 <code>order_manager</code>는 단순 server가 아니다. 외부에서는 주문을 처리하는 service server로 보이지만, 내부에서는 다른 service들을 호출하는 client다. 이 패턴은 실제 로봇 시스템에서도 자주 쓰인다. 예를 들어 manipulation task server가 perception service, planning service, gripper service를 순서대로 호출해 하나의 작업을 완성할 수 있다.</p>
<h3 id="143-build와-실행-흐름">1.4.3. Build와 실행 흐름</h3>
<p>Workspace를 만든 뒤에는 <code>src</code> 아래 package를 배치하고 <code>colcon build</code>로 빌드한다. Interface package가 포함되어 있다면 <code>.srv</code> 파일로부터 생성된 코드가 만들어진다. 이후 <code>source install/local_setup.bash</code>를 실행해야 <code>ros2 run</code>으로 node를 실행하거나 Python에서 interface를 import할 수 있다.</p>
<p>실행할 때는 service server node들이 먼저 준비되어야 한다. 예를 들어 <code>stock_server</code>, <code>payment_server</code>, <code>discount_server</code>가 실행되고 나서 <code>order_manager</code>가 이 service client들을 사용할 수 있다. <code>order_client</code>가 주문을 보내면 <code>order_manager</code>는 request를 받고, 재고 확인과 결제 승인 결과를 종합해 최종 response를 반환한다. <code>log_monitor</code>는 처리 결과를 별도로 관찰하거나 기록하는 node로 볼 수 있다.</p>
<p>이 실습에서 배울 점은 <code>.srv</code>가 node 사이에서 어떤 데이터를 주고받을지 정하는 계약이라는 점이다. Workspace는 여러 package를 함께 빌드하는 작업 공간이고, interface package는 통신 형식을 생성하며, node package는 그 형식을 사용해 server/client 동작을 구현한다. 이 세 구조가 분리되어야 service 정의를 재사용하고, 구현 node를 바꾸더라도 같은 interface를 기준으로 시스템을 유지할 수 있다.</p>
<h3 id="144-workspace-package-interface-실습-정리">1.4.4. Workspace, Package, Interface 실습 정리</h3>
<ul>
<li><strong>실습에서 이해할 점</strong></li>
</ul>
<p>ROS2 실습의 핵심은 node를 실행했다는 사실이 아니라, 여러 node가 서로 다른 책임을 가지고 통신한다는 구조를 이해하는 것이다. Topic은 지속 데이터 흐름, Service는 요청/응답, Action은 시간이 걸리는 목표 수행에 맞다. Launch는 여러 node와 설정을 하나의 실행 시나리오로 묶고, Parameter는 코드와 실험 조건을 분리한다.</p>
<p>이 개념들이 합쳐지면 로봇 시스템을 설계할 수 있다. 카메라 node는 image topic을 publish하고, perception node는 image를 subscribe해 detection result를 publish한다. Planning node는 detection result를 받아 목표 pose를 만들고, MoveIt action이나 controller에 trajectory를 보낸다. RViz는 TF와 topic을 시각화한다. 이런 전체 흐름이 ROS2 위에서 구성된다.</p>
<ul>
<li><strong>Workspace가 담당하는 것</strong></li>
</ul>
<p>새로 확인한 <code>ROS/ROS_실습코드/ROS_실습코드</code>와 <code>ROS/backup_ros_code/backup_ros_data-001</code> 안에는 <code>svc_ws</code>, <code>my_pubsub</code>, <code>my_action</code>, <code>launch_ws</code>, <code>param_ws</code>, <code>gazebo_ws</code>, <code>multi_turtle_ws</code>, <code>move_urdf</code>, <code>depth_ws</code>, <code>ws_moveit</code> 같은 workspace가 들어 있다. 여기서 workspace는 “코드를 모아 둔 폴더”가 아니라 여러 package를 같은 빌드 환경에서 해석하고, 생성된 interface와 실행 파일을 하나의 ROS2 환경으로 묶는 단위다.</p>
<p><code>src</code> 아래에는 사람이 작성한 package가 들어가고, <code>colcon build</code> 이후에는 <code>build</code>, <code>install</code>, <code>log</code>가 생긴다. 개념 정리에서 중요한 것은 <code>build/install/log</code> 산출물이 아니라 <code>src</code> 아래의 package 구조다. 예를 들어 <code>svc_ws/src/smart_shop_interfaces</code>는 통신 형식을 정의하고, <code>svc_ws/src/smart_shop_nodes</code>는 그 형식을 실제 node 동작으로 사용한다. 이 분리가 되어야 interface를 여러 node가 공유할 수 있고, server 구현을 바꾸더라도 client는 같은 <code>.srv</code> 계약을 기준으로 동작할 수 있다.</p>
<ul>
<li><strong>Interface package가 담당하는 것</strong></li>
</ul>
<p><code>smart_shop_interfaces</code>에는 <code>srv</code>와 <code>msg</code>가 함께 있다. <code>CheckStock.srv</code>는 <code>item_id</code>, <code>quantity</code>를 요청으로 받고 <code>available</code>, <code>remaining</code>, <code>reason</code>을 응답한다. 즉 재고 확인이라는 기능을 “어떤 입력으로 묻고 어떤 출력으로 판단할지” 정한다. <code>AuthorizePayment.srv</code>는 <code>order_id</code>, <code>amount</code>, <code>currency</code>를 받아 <code>approved</code>, <code>auth_code</code>, <code>reason</code>을 돌려준다. 결제 서버 내부 구현이 실제 카드 결제든 더미 승인 로직이든 client는 이 응답 필드만 보고 다음 흐름을 결정할 수 있다.</p>
<p><code>PlaceOrder.srv</code>는 주문 전체를 대표하는 service interface다. 요청에는 <code>order_id</code>, <code>item_id</code>, <code>quantity</code>, <code>amount</code>, <code>currency</code>가 들어가고, 응답에는 <code>success</code>, <code>status</code>, <code>detail</code>, <code>remaining_stock</code>, <code>payment_auth_code</code>가 들어간다. 여기서 응답 필드는 단순 성공/실패만 말하지 않는다. 왜 실패했는지, 재고가 얼마나 남았는지, 결제 승인 코드가 무엇인지까지 다음 node나 사용자에게 전달한다.</p>
<p><code>DiscountApply.srv</code>는 할인 계산을 별도 service로 분리한다. <code>item_id</code>, <code>original_amount</code>를 요청하고 <code>discounted_amount</code>, <code>discount_rate</code>, <code>reason</code>을 응답하게 되어 있다. 이 구조는 주문 manager가 할인 정책을 직접 품지 않고, 할인 판단을 독립 node로 위임할 수 있게 한다.</p>
<p><code>OrderLog.msg</code>는 service 응답과 다르게 지속 관찰을 위한 topic 메시지다. <code>order_id</code>, <code>item_id</code>, <code>quantity</code>, <code>amount</code>, <code>success</code>, <code>status</code>, <code>detail</code>, <code>timestamp</code>를 담아 주문 처리 결과를 <code>order_log</code> topic으로 흘린다. service가 “이번 주문을 처리해 달라”는 요청/응답이라면, topic log는 “처리 결과가 발생했다”는 사건 기록이다.</p>
<ul>
<li><strong>Node package가 담당하는 것</strong></li>
</ul>
<p><code>smart_shop_nodes</code>는 interface를 실제 동작으로 바꾸는 package다. <code>stock_server.py</code>는 <code>CheckStock</code> service server로 재고 가능 여부를 판단하고, <code>payment_server.py</code>는 <code>AuthorizePayment</code> server로 결제 승인 여부를 판단한다. <code>discount_server.py</code>는 할인율과 할인 금액을 계산한다.</p>
<p>핵심은 <code>order_manager.py</code>다. 이 node는 <code>place_order</code> service server이면서 동시에 <code>check_stock</code>, <code>authorize_payment</code>, <code>discount_apply</code> service client다. 주문 요청이 오면 먼저 재고 service를 호출하고, 재고가 부족하면 <code>rejected</code> 상태를 응답한다. 재고가 있으면 할인 service로 최종 금액을 계산하고, 그 금액으로 결제 service를 호출한다. 결제가 거절되면 결제 실패 이유를 응답하고, 모두 성공하면 <code>success</code> 상태와 결제 승인 코드를 응답한다.</p>
<p>이 구조가 중요한 이유는 하나의 node가 “모든 일을 직접 처리하는 거대한 함수”가 아니라, 여러 service를 조합하는 orchestration node가 될 수 있음을 보여 주기 때문이다. 실제 로봇에서도 task manager가 perception service, motion planning service, gripper service, safety check service를 순서대로 호출해 하나의 작업을 완성하는 구조가 자주 쓰인다.</p>
<ul>
<li><strong>Topic과 Service가 함께 쓰이는 이유</strong></li>
</ul>
<p><code>order_manager.py</code>는 최종 응답을 client에게 돌려주는 것과 별도로 <code>OrderLog</code> 메시지를 <code>order_log</code> topic으로 publish한다. <code>log_monitor.py</code>는 이 topic을 subscribe해서 주문 성공/실패 누적 개수를 세고 로그를 출력한다.</p>
<p>여기서 service와 topic의 역할 차이가 분명해진다. <code>order_client</code>는 주문 처리 결과를 한 번 받아야 하므로 service response가 필요하다. 반면 <code>log_monitor</code>는 주문 요청의 당사자가 아니어도 전체 주문 처리 흐름을 계속 관찰해야 하므로 topic subscription이 적합하다. 하나의 사건이 “요청자에게는 response”이고 “감시자에게는 event stream”이 되는 것이다.</p>
<ul>
<li><strong>Action 실습이 보여 주는 장기 작업 구조</strong></li>
</ul>
<p><code>my_action/src/my_action_interfaces/action/PatrolTest.action</code>은 waypoint 목록과 tolerance를 goal로 받고, 현재 waypoint index와 남은 거리를 feedback으로 보내며, 최종적으로 성공 여부와 메시지를 result로 돌려주는 구조다. Turtlesim patrol server는 <code>/turtle1/pose</code>를 subscribe하고 <code>/turtle1/cmd_vel</code>을 publish하면서 goal로 받은 waypoint를 차례로 따라간다.</p>
<p>이 실습에서 action이 필요한 이유는 patrol이 즉시 끝나는 계산이 아니기 때문이다. Client는 목표 waypoint 묶음을 보내고, server는 이동 중에 계속 remaining distance를 feedback으로 보낸다. 사용자는 중간에 cancel할 수 있고, server는 cancel 요청을 받으면 속도를 0으로 publish하고 작업을 정리한다. 이것이 service와 action의 가장 실질적인 차이다.</p>
<ul>
<li><strong>실습 코드를 읽을 때의 기준</strong></li>
</ul>
<p>ROS2 코드를 볼 때는 파일 이름보다 책임을 먼저 봐야 한다. Interface package는 데이터 계약을 만든다. Node package는 그 계약을 사용해 publisher, subscriber, service server, service client, action server, action client를 구현한다. Launch package는 여러 node와 parameter를 한 번에 실행한다. 이 네 층을 구분하면 ROS2가 단순 명령어 모음이 아니라 분산 로봇 시스템을 구성하는 구조라는 점이 보인다.</p>
<ul>
<li><strong>한 줄 정리</strong></li>
</ul>
<p>ROS2는 로봇 시스템을 node로 나누고, topic/service/action/launch/parameter를 통해 기능들이 협력하도록 만드는 분산 로봇 미들웨어다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Project] MacGyvBot 로봇틱스 프로젝트 정리]]></title>
            <link>https://velog.io/@jack_7711/Project-MacGyvBot-%EB%A1%9C%EB%B4%87%ED%8B%B1%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Project-MacGyvBot-%EB%A1%9C%EB%B4%87%ED%8B%B1%EC%8A%A4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 21 Jun 2026 16:56:56 GMT</pubDate>
            <description><![CDATA[<h1 id="macgyvbot-포트폴리오-정리">MacGyvBot 포트폴리오 정리</h1>
<h2 id="프로젝트-요약">프로젝트 요약</h2>
<p><strong>MacGyvBot: 음성/GUI 기반 공구 전달 및 반납 로봇 어시스턴트</strong></p>
<p>MacGyvBot은 작업자가 공구 보관 장소까지 직접 이동하지 않아도, 로봇팔이 필요한 공구를 찾아 전달하고 사용 후 다시 서랍에 정리하는 ROS 2 기반 로봇 어시스턴트 프로젝트이다. 사용자는 음성 또는 GUI로 &quot;드라이버 가져다줘&quot;, &quot;이 공구 정리해줘&quot;, &quot;멈춰&quot;, &quot;재개&quot; 같은 명령을 입력하고, 시스템은 이를 구조화된 robot task로 변환한다.</p>
<p>전체 시스템은 Command, Task Coordinator, Perception, Manipulation, Operator UI, Safety 계층으로 구성했다. ROS 2의 node, topic, service, action 개념을 기준으로 기능 책임을 분리하고, 센서 데이터와 detection 결과처럼 지속적으로 흐르는 정보는 topic으로, 명확한 요청/응답이 필요한 판단은 service로, 시간이 걸리고 중간 취소가 필요한 manipulation 흐름은 action과 task queue로 관리하는 방향을 잡았다.</p>
<p>Perception은 RealSense RGB-D, YOLO, SAM+Depth, PCA, hand landmark ML classifier를 활용해 공구 위치, 파지점, 방향각, 사용자 handoff 상태를 판단한다. Manipulation은 Doosan M0609, MoveIt, OnRobot RG2 gripper를 사용해 서랍 접근, 공구 파지, 사용자 전달, 반납, 서랍 닫기 동작을 수행한다.</p>
<h2 id="내-역할">내 역할</h2>
<p>프로젝트에서 나는 PM 및 통합 담당 역할을 수행했다. 일정 관리, 업무 분담, QA, 시연 시나리오 구성, 발표 흐름 정리, 팀원 간 커뮤니케이션 조율을 맡았다.</p>
<p>기술적으로는 ROS 2 패키지 책임 분리, perception 방식 비교, YOLO 학습/평가 방향 제시, VLM/VLM-only/API 기반 grasp point 실험, SAM+Depth mask와 PCA 기반 yaw 계산 검증, GUI 개선 아이디어, structured log 통일, 코드 리팩토링, TaskStep Queue 기반 멈춤/재개/recovery 구조 설계에 참여했다.</p>
<p>또한 실제 로봇 시연 과정에서 발생한 planning 실패, depth projection 실패, handoff 실패, 서랍 충돌, return drawer validation 실패, wrist joint branch 문제를 QA 로그로 정리하고, 원인을 perception, TF/depth, MoveIt planning scene, controller, gripper, task orchestration 계층으로 나누어 개선 방향을 조율했다.</p>
<h2 id="핵심-기술-스택">핵심 기술 스택</h2>
<ul>
<li>Language: Python</li>
<li>Robotics: ROS 2 Humble, MoveIt, MoveItPy, ros2_control, RViz</li>
<li>Robot Hardware: Doosan M0609, OnRobot RG2 Gripper</li>
<li>Vision: Intel RealSense D435I, YOLO, SAM, Depth Mask, PCA, image preprocessing, segmentation</li>
<li>AI / ML: VLM, Gemini API, SmolVLM, Qwen 3B/7B, hand landmark ML classifier</li>
<li>Robot Modeling / Simulation: URDF, Xacro, TF, Isaac Sim</li>
<li>UI: PyQt 기반 Operator GUI</li>
<li>Collaboration: GitHub, Google Drive, QA 문서, 발표/시연 문서화</li>
</ul>
<h2 id="핵심-구현-및-기여">핵심 구현 및 기여</h2>
<h3 id="1-ros-2-기반-패키지-구조와-통신-흐름-정리">1. ROS 2 기반 패키지 구조와 통신 흐름 정리</h3>
<p>초기에는 기능들이 하나의 흐름 안에 섞여 있어 문제가 발생했을 때 원인을 추적하기 어려웠다. 이를 Command, Task, Perception, Manipulation, UI, Config, Interfaces 등 역할별 패키지 구조로 바라보고, 각 계층이 ROS topic/service/message 계약을 통해 연결되도록 정리했다.</p>
<p>이 과정에서 ROS 2를 단순 실행 도구가 아니라 분산 로봇 시스템의 구조로 이해했다. 카메라 이미지, detection result, task status, joint state처럼 계속 갱신되는 데이터는 topic으로 흐르게 하고, perception 요청이나 상태 확인처럼 요청/응답이 명확한 동작은 service 성격으로, 로봇 팔 이동이나 pick-and-place처럼 시간이 걸리고 취소가 필요한 작업은 action/task step으로 관리하는 기준을 세웠다.</p>
<p>이 구조 덕분에 자연어 명령 오류, perception 실패, MoveIt planning 실패, UI 표시 문제를 각각 분리해서 디버깅할 수 있었다.</p>
<h3 id="2-taskstep-queue-기반-작업-흐름-설계">2. TaskStep Queue 기반 작업 흐름 설계</h3>
<p>bring/return은 단일 동작이 아니라 서랍 접근, 공구 탐지, depth 보정, 파지, 전달, 반납, 복구가 연결된 긴 흐름이다. ROS 2 Action만으로는 전체 작업의 중간 상태, 남은 단계, 복구 후 재개를 관리하기 어렵다고 판단했다.</p>
<p>그래서 작업을 TaskStep 단위로 나누고 queue로 관리하는 구조를 적용했다. pause 시 현재 MoveIt goal을 cancel하고 suspended step과 남은 queue를 보존하며, resume 시 중단된 step부터 다시 실행하도록 설계했다. cancel과 exit도 구분해 cancel은 queue 정리, exit는 home 복귀와 gripper open까지 포함하도록 분리했다.</p>
<p>이를 통해 pause, resume, cancel, drop recovery 후 원래 작업 복귀를 더 유연하게 처리할 수 있었다.</p>
<h3 id="3-cv-학습-흐름을-실제-로봇-perception-판단으로-연결">3. CV 학습 흐름을 실제 로봇 perception 판단으로 연결</h3>
<p>concept notes에서 정리한 CV 흐름은 픽셀 전처리, feature extraction, CNN, object detection, segmentation, multimodal model로 확장된다. MacGyvBot에서는 이 흐름을 단순 학습 내용으로 두지 않고, 실제 perception pipeline 판단 기준으로 연결했다.</p>
<p>이미지 전처리 관점에서는 조명, 대비, 노이즈, ROI가 thresholding, segmentation, detection 결과를 흔들 수 있음을 고려했다. Detection 관점에서는 YOLO가 class와 bbox를 잘 내더라도 bbox가 실제 grasp pipeline에 사용할 수 있는 품질인지 따로 보았다. Segmentation 관점에서는 bounding box보다 실제 공구 영역 mask가 파지점과 yaw 추정에 더 직접적인 정보를 준다고 판단했다.</p>
<p>최종적으로는 task-specific YOLO로 공구 후보와 grasp point의 x, y를 안정화하고, SAM+Depth mask에서 실제 공구 영역을 확보한 뒤, PCA로 긴 축을 계산해 yaw를 얻는 방식이 실제 로봇 제어에 더 적합하다고 판단했다.</p>
<h3 id="4-depth-calibration-tf-기반-2d-to-3d-연결-정리">4. Depth, Calibration, TF 기반 2D-to-3D 연결 정리</h3>
<p>YOLO나 SAM의 결과는 이미지 좌표계에 있는 2D 정보이므로 로봇이 바로 사용할 수 없다. Depth 값, camera intrinsic, hand-eye calibration, TF 변환을 거쳐 camera frame의 3D point를 robot base frame의 목표 pose로 바꿔야 한다.</p>
<p>이 관점에서 depth=0, camera info 불일치, frame transform 오류가 겉으로는 perception 실패나 planning 실패처럼 보일 수 있음을 QA 기준에 포함했다. 실제 pick target 계산에서는 bbox center나 mask point를 depth와 결합하고, TF를 통해 MoveIt이 해석할 수 있는 frame으로 변환하는 흐름을 점검했다.</p>
<p>이 경험을 통해 &quot;CV가 물체를 찾았다&quot;와 &quot;로봇이 그 물체를 잡을 수 있다&quot; 사이에는 depth projection, calibration, TF, safe workspace clamp가 반드시 필요하다는 점을 프로젝트 설명의 핵심 메시지로 정리했다.</p>
<h3 id="5-moveit-urdfxacro-collision-scene-기반-manipulation-디버깅">5. MoveIt, URDF/Xacro, collision scene 기반 manipulation 디버깅</h3>
<p>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를 함께 확인했다.</p>
<p>서랍 collision scene 문제에서는 collision object가 안전성을 높이지만, 크기나 적용 시점이 보수적이면 gripper 접근 경로까지 막아 planning이 실패할 수 있음을 확인했다. 따라서 collision object는 &quot;많이 넣을수록 안전하다&quot;가 아니라 실제 작업 가능성과 균형을 맞춰야 한다고 정리했다.</p>
<p>또한 wrist joint branch 문제에서는 같은 end-effector pose에도 여러 IK 해가 존재할 수 있음을 바탕으로, 현재 joint state와 가장 가까운 후보를 선택하고 joint_6 equivalent angle을 비교하는 방향을 제안했다.</p>
<h3 id="6-handoff-안전성-개선-방향-정리">6. Handoff 안전성 개선 방향 정리</h3>
<p>초기 handoff 판단은 손과 공구의 거리, overlap, depth 조건을 조합한 rule-based 방식이었다. 그러나 손이 실제로 공구를 잡지 않았는데도 release 조건이 만족될 수 있어 안전 문제가 있었다.</p>
<p>이를 해결하기 위해 판단 기준을 &quot;손이 공구 근처에 있는가&quot;에서 &quot;손이 grasp gesture를 하고 있고 실제 공구 표면과 접촉했는가&quot;로 바꾸었다. hand landmark ML classifier로 open/grasp를 분류하고, SAM+Depth mask로 공구 표면을 유지하며, 손 landmark와 mask/depth 접촉 및 시간 안정성을 함께 확인하는 구조로 개선했다.</p>
<p>이 방향은 handoff를 단순 인식 결과가 아니라 release 전 safety gate로 다루는 데 의미가 있었다.</p>
<h3 id="7-isaac-sim과-시뮬레이션-기반-검증-관점-반영">7. Isaac Sim과 시뮬레이션 기반 검증 관점 반영</h3>
<p>Isaac Sim은 센서, 물체, 로봇 제어, 물리 환경을 한 장면 안에서 검증할 수 있는 시뮬레이션 환경이다. 프로젝트에서는 실제 로봇 실험의 한계를 보완하기 위해 Isaac Sim을 활용해 pick-and-place 구조, gripper assembly, sensor simulation, controller 흐름을 검증하는 방향을 검토했다.</p>
<p>특히 서랍 개폐나 handoff 같은 접촉 기반 동작은 단순 transform 애니메이션보다 joint constraint, collider, rigid body, contact sensor 같은 물리 설정이 중요하다고 보았다. 이 관점은 실제 로봇에서 collision scene과 gripper 접촉 문제가 발생했을 때 원인을 더 구조적으로 나누는 데 도움이 되었다.</p>
<h3 id="8-qa-및-structured-log-정리">8. QA 및 structured log 정리</h3>
<p>실제 로봇 테스트에서는 &quot;멈춰 후 재개 불가&quot;, &quot;drawer_prepare_failed&quot;, &quot;depth=0으로 pick target 보정 실패&quot;, &quot;return drawer에 다른 공구 감지&quot;, &quot;joint_6 목표각 branch 문제&quot;, &quot;서랍 collision scene이 planning을 막는 문제&quot; 등이 발생했다.</p>
<p>각 로그를 <code>[pkg]</code>, <code>[pipe]</code>, <code>[msg]</code>, <code>[reason]</code>, <code>[tool]</code>, <code>[stage]</code> 형식으로 정리하여 어느 계층에서 실패했는지 빠르게 파악할 수 있도록 했다. 이는 팀원들이 각자 다른 방식으로 로그를 남기던 문제를 줄이고, QA와 트러블슈팅 속도를 높이는 데 도움이 되었다.</p>
<h2 id="트러블슈팅-정리">트러블슈팅 정리</h2>
<h3 id="문제-1-vlm-기반-grasp-point-추론의-불안정성">문제 1. VLM 기반 grasp point 추론의 불안정성</h3>
<p><strong>문제 상황</strong><br>초기에는 VLM이 이미지를 보고 적절한 grasp point와 yaw를 추론하도록 구성하려 했다. SmolVLM, Qwen 3B/7B, Gemini API, grid prompt 방식 등을 실험했지만, 프롬프트에 따라 결과가 흔들리고 추론 시간이 길어 실제 로봇 제어 입력으로 사용하기 어려웠다.</p>
<p><strong>원인</strong><br>VLM foundation model은 일반적인 이미지 이해에는 강점이 있지만, 특정 공구의 실제 파지 가능 지점과 로봇 gripper 방향각을 안정적으로 출력하기에는 도메인 데이터와 fine-tuning이 부족했다. 또한 실제 로봇 제어에는 픽셀 좌표의 작은 오차도 큰 실패로 이어질 수 있었다.</p>
<p><strong>해결</strong><br>VLM 단독 방식을 최종 제어 입력으로 사용하지 않고, task-specific YOLO와 SAM+Depth+PCA 기반 방식으로 전환했다. YOLO는 공구 및 grasp point의 x, y 좌표를 안정화하고, SAM mask와 depth는 실제 공구 영역을 보강하며, PCA는 mask에서 공구의 긴 축을 계산해 yaw를 제공하도록 했다.</p>
<p><strong>결과</strong><br>범용 AI 모델보다 도메인 특화 모델과 기하학적 알고리즘을 조합하는 방식이 실제 로봇 환경에서 더 빠르고 안정적이라는 결론을 얻었다.</p>
<h4 id="추가-정리-vlavlm을-바로-적용하지-않고-task-specific-perception으로-전환한-이유">추가 정리. VLA/VLM을 바로 적용하지 않고 task-specific perception으로 전환한 이유</h4>
<p>초기에는 최근 로봇 연구에서 자주 사용되는 VLM + VLA 구조도 고려했다. VLM이 사용자의 명령을 바탕으로 전체 작업 계획을 세우고, VLA가 현재 카메라 프레임을 보며 다음 행동 또는 짧은 행동 시퀀스를 예측해 로봇을 움직이는 구조를 생각했다.</p>
<p>하지만 실제 프로젝트에서는 VLA를 바로 적용하기 어려운 제약이 있었다. VLA는 현재 상태에서 다음 행동을 예측하는 방식이기 때문에 long-horizon task 전체를 안정적으로 수행하려면 실시간성, 제어 주기, 실패 복구, 환경 변화 추적 문제가 함께 해결되어야 했다. 또한 이 프로젝트에서는 MoveIt을 통해 좌표 기반 motion planning을 이미 처리하고 있었기 때문에, VLA가 직접 action을 예측하는 구조는 오히려 시스템을 복잡하게 만들 수 있었다.</p>
<p>그래서 처음에는 VLM을 활용해 공구 이미지에서 grasp point와 yaw를 직접 얻으려 했다. VLM only 방식, YOLO bbox crop 후 grid를 나누어 VLM이 잡기 좋은 cell을 고르는 방식, Gemini API를 활용하는 방식까지 비교했다. Grid 방식은 VLM이 완전히 엉뚱한 곳을 고르는 문제를 줄일 수 있었지만, latency가 증가했고 결과의 일관성을 완전히 보장하지 못했다. Qwen 3B/7B처럼 더 큰 모델도 사용해 봤지만 추론 시간은 늘어난 반면 실제 로봇 제어에 믿고 넣을 만큼 안정적인 x, y, yaw를 제공하지는 못했다.</p>
<p>결국 이 문제는 &quot;일반적인 VLM이 모든 상황에서 grasp point를 알아서 찾아줄 것&quot;이라는 기대가 너무 낙관적이었다는 결론으로 이어졌다. 실제 로봇 manipulation에서는 한두 픽셀의 오차, yaw 계산 실패, 마스크 흔들림이 바로 grasp 실패나 충돌 위험으로 이어질 수 있었다.</p>
<p>최종적으로는 task-specific YOLO로 공구와 grasp point를 직접 탐지하고, SAM과 depth mask를 결합해 공구 영역을 안정화한 뒤, PCA로 공구의 긴 축을 계산해 yaw를 얻는 구조를 선택했다. 공구 대부분이 길쭉한 형태라는 도메인 특성을 활용했기 때문에 PCA 기반 yaw 계산이 잘 맞았고, VLM보다 범용성은 낮지만 실제 시연 환경에서는 더 예측 가능하고 디버깅하기 쉬운 방식이었다.</p>
<p>최종 perception 흐름은 다음과 같이 정리할 수 있다.</p>
<pre><code class="language-text">사용자 명령
-&gt; 대상 공구 결정
-&gt; YOLO로 공구 / grasp point 탐지
-&gt; SAM + Depth mask로 공구 영역 보정
-&gt; PCA로 yaw 계산
-&gt; MoveIt으로 접근 및 grasp 수행
-&gt; 실패 시 recovery sequence 실행</code></pre>
<p>이 과정에서 얻은 가장 큰 교훈은 로봇 제어에서는 &quot;똑똑한 모델 하나&quot;보다 &quot;불확실성을 줄이는 작은 모듈들의 조합&quot;이 더 실용적일 때가 많다는 점이다. VLM/VLA는 향후 planner나 action adapter 형태로 확장할 수 있지만, 실제 제어 입력은 반복 가능하고 실패 원인을 추적할 수 있는 구조가 먼저 필요했다.</p>
<h3 id="문제-2-yolo-bbox는-성공했지만-실제-grasp로-이어지지-않는-문제">문제 2. YOLO bbox는 성공했지만 실제 grasp로 이어지지 않는 문제</h3>
<p><strong>문제 상황</strong><br>YOLO가 공구를 검출해도 bbox가 공구 본체를 충분히 포함하지 않거나, 서랍 내부/그리퍼 접근 순간/부분 가림 상황에서 bbox가 흔들리면 후속 SAM, depth mask, PCA yaw 계산이 실패했다.</p>
<p><strong>원인</strong><br>객체 탐지의 성공 기준과 로봇 파지 성공 기준이 달랐다. 단순히 class가 맞는 것만으로는 충분하지 않았고, bbox가 후속 grasp pipeline에 사용할 수 있는 품질이어야 했다. confidence가 높아도 box 위치가 부정확하거나 NMS/threshold 설정 때문에 목표가 사라지면 로봇 작업은 실패할 수 있었다.</p>
<p><strong>해결</strong><br>YOLO 평가 기준을 단순 mAP가 아니라 &quot;grasp pipeline에 사용할 수 있는 bbox인지&quot;로 재정의했다. 클래스가 맞는지, 공구 본체를 충분히 포함하는지, SAM/depth/PCA로 이어질 수 있는지를 success condition으로 잡았다. 또한 runtime confidence threshold, NMS 영향, condition별 success rate, bbox usable for grasp rate를 평가하도록 정리했다.</p>
<p><strong>결과</strong><br>Perception 결과를 로봇 작업 관점에서 평가하는 기준을 세웠고, 발표와 QA에서도 &quot;AI가 잘 된다&quot;가 아니라 &quot;후속 grasp에 쓸 수 있는가&quot;를 중심으로 설명할 수 있게 되었다.</p>
<h3 id="문제-3-depth-projection과-tf-변환-실패">문제 3. depth projection과 TF 변환 실패</h3>
<p><strong>문제 상황</strong><br>Detection이나 segmentation 결과가 있어도 depth 값이 0이거나 camera frame에서 robot base frame으로 변환이 맞지 않으면 pick target이 엉뚱한 위치로 계산되었다.</p>
<p><strong>원인</strong><br>2D 이미지 좌표는 로봇의 목표 pose가 아니다. 픽셀 좌표를 3D camera coordinate로 바꾸려면 depth와 camera intrinsic이 필요하고, 로봇이 움직이려면 hand-eye calibration과 TF를 통해 base frame으로 변환해야 한다. 이 중 하나라도 틀리면 perception 오류처럼 보이지만 실제 원인은 좌표계 연결일 수 있다.</p>
<p><strong>해결</strong><br>depth topic과 camera info topic을 함께 확인하고, depth=0인 경우를 명시적으로 실패 처리하도록 QA 기준에 포함했다. 또한 RViz에서 TF frame과 marker 위치를 확인해 detection result, camera frame, robot base frame, MoveIt target pose가 같은 좌표 흐름 안에 있는지 점검했다.</p>
<p><strong>결과</strong><br>perception과 manipulation 사이의 실패 지점을 더 정확히 나눌 수 있었고, &quot;검출 성공&quot; 이후에도 depth/calibration/TF 검증이 필요하다는 점을 팀 내 공통 기준으로 만들 수 있었다.</p>
<h3 id="문제-4-pauseresume이-실제-복합-작업-흐름에서-안정적으로-동작하지-않음">문제 4. pause/resume이 실제 복합 작업 흐름에서 안정적으로 동작하지 않음</h3>
<p><strong>문제 상황</strong><br>서랍 접근, drawer observe, pick/refine step 중 &quot;멈춰&quot;를 입력하면 현재 MoveIt goal은 취소되지만, 이후 &quot;재개&quot; 시 어느 단계부터 다시 실행해야 하는지 불명확한 문제가 있었다. 일부 상황에서는 drawer_prepare_failed로 재개가 실패하거나, task step 시작 전 pause 시 resume이 불가능했다.</p>
<p><strong>원인</strong><br>bring/return은 단일 action goal이 아니라 여러 단계가 연결된 복합 작업이다. 현재 step, 남은 queue, target tool, perception 결과, recovery 상태를 함께 보존하지 않으면 중단 이후 재개할 수 없다.</p>
<p><strong>해결</strong><br>TaskStep Queue 개념을 도입해 전체 작업을 작은 단계로 분해했다. pause 시 현재 MoveIt goal을 cancel하고 suspended step과 남은 queue를 보존하며, resume 시 중단된 step부터 다시 실행하도록 설계했다.</p>
<p><strong>결과</strong><br>작업 흐름이 긴 스크립트가 아니라 중지, 재개, 취소, 복구가 가능한 상태 기반 구조로 개선되었다.</p>
<h3 id="문제-5-handoff-과정에서-사용자-손-인식과-release-판단이-불안정함">문제 5. handoff 과정에서 사용자 손 인식과 release 판단이 불안정함</h3>
<p><strong>문제 상황</strong><br>초기 rule-based handoff 판단은 손과 공구가 가까워지거나 ROI가 겹치면 사용자가 공구를 잡았다고 판단할 수 있었다. 하지만 실제로는 손이 공구를 잡지 않았는데도 release가 발생할 수 있어 위험했다. 반대로 손이나 그리퍼가 공구를 가리면 YOLO bbox가 사라져 판단 자체가 어려웠다.</p>
<p><strong>원인</strong><br>bbox와 거리 기반 규칙만으로는 실제 &quot;사람이 공구를 잡았다&quot;는 상태를 안정적으로 판단하기 어려웠다. 특히 사용자 손과 로봇 gripper가 가까운 상황에서는 false positive가 안전 문제로 이어질 수 있었다.</p>
<p><strong>해결</strong><br>판단 기준을 &quot;손이 공구 근처에 있는가&quot;에서 &quot;손이 grasp gesture를 하고 있고 실제 공구 표면과 접촉했는가&quot;로 바꾸었다. hand landmark ML classifier로 open/grasp를 분류하고, SAM+Depth mask로 공구 표면을 유지하며, 손 landmark와 mask/depth 접촉 및 시간 안정성을 함께 확인하도록 구성했다.</p>
<p><strong>결과</strong><br>로봇이 공구를 너무 일찍 놓는 위험을 줄이고, handoff 판단을 safety gate 기반으로 강화할 수 있었다.</p>
<h3 id="문제-6-서랍-collision-scene이-안전성을-높이지만-planning을-막는-문제">문제 6. 서랍 collision scene이 안전성을 높이지만 planning을 막는 문제</h3>
<p><strong>문제 상황</strong><br>서랍을 collision object로 planning scene에 넣으면 로봇이 위험한 경로를 피할 수 있지만, 일부 경우에는 gripper와 drawer collision object가 너무 보수적으로 충돌 판정되어 planning이 실패했다.</p>
<p><strong>원인</strong><br>실제 로봇에서는 서랍 손잡이를 잡고 접근해야 하는데, collision scene이 이를 단순 장애물로만 인식하면 필요한 접근 경로까지 막을 수 있다. 안전을 위한 모델링이 오히려 작업 실행을 방해하는 상충 관계가 생겼다.</p>
<p><strong>해결</strong><br>RViz와 MoveIt planning scene을 함께 확인하면서 collision object 적용 범위와 시점을 조정했다. URDF/Xacro의 visual, collision, inertial 차이를 구분하고, collision geometry가 실제 작업 가능성을 과하게 막지 않는지 확인하는 기준을 세웠다.</p>
<p><strong>결과</strong><br>안전 기능은 단순히 많이 넣는 것이 아니라, 실제 작업 가능성과 균형을 맞춰야 한다는 것을 배웠다.</p>
<h3 id="문제-7-wrist-joint-branch-선택으로-의도하지-않은-큰-회전-발생">문제 7. wrist joint branch 선택으로 의도하지 않은 큰 회전 발생</h3>
<p><strong>문제 상황</strong><br>MoveIt이 pose goal을 만족하는 IK 해를 선택할 때 현재 자세와 멀리 떨어진 branch를 선택하면 손목 관절이 불필요하게 크게 회전하거나 joint limit에 가까워지는 문제가 발생했다.</p>
<p><strong>원인</strong><br>같은 end-effector pose라도 여러 IK 해가 존재할 수 있고, MoveIt 내부 선택에만 맡기면 현재 관절 상태에서 가장 자연스러운 해가 선택된다는 보장이 없었다.</p>
<p><strong>해결</strong><br>현재 joint state를 기준으로 여러 IK 후보를 비교하고, joint delta가 가장 작은 후보를 선택하는 방향으로 개선했다. 특히 joint_6에 대해서 equivalent angle 후보를 만들고, joint limit과 현재 각도 차이를 기준으로 필터링했다.</p>
<p><strong>결과</strong><br>의도하지 않은 손목 회전 위험을 줄이고, 실제 로봇 동작의 예측 가능성을 높였다.</p>
<h3 id="문제-8-실제-시연은-성공-케이스보다-실패복구-시나리오-설계가-중요함">문제 8. 실제 시연은 성공 케이스보다 실패/복구 시나리오 설계가 중요함</h3>
<p><strong>문제 상황</strong><br>처음에는 기본 bring/return 성공 시연에 집중했지만, 실제 로봇에서는 공구 없음, 다른 공구 감지, handoff 실패, drop, planning 실패, 멈춤/재개 실패 등 다양한 상황이 발생했다.</p>
<p><strong>원인</strong><br>실제 작업 환경은 항상 정상 상태가 아니며, 로봇 시스템은 실패 상황을 설명하고 안전하게 멈추거나 복구해야 한다.</p>
<p><strong>해결</strong><br>시연 시나리오를 기본 bring/return뿐 아니라 drop 성공/실패, 멈춤-재개, inspection 실패, handoff 실패, drawer에 다른 공구가 있는 경우, 서랍에 공구가 없는 경우, return grasp 실패 등으로 확장했다. Isaac Sim과 RViz 관점에서는 시뮬레이션/시각화가 단순 화면 확인이 아니라 sensor, TF, planning scene, controller 상태를 검증하는 도구라는 점도 함께 설명했다.</p>
<p><strong>결과</strong><br>포트폴리오 관점에서 단순 데모 구현이 아니라 QA, 실패 정의, recovery 설계까지 고려한 프로젝트로 정리할 수 있게 되었다.</p>
<h2 id="한-줄-요약">한 줄 요약</h2>
<p>ROS 2, MoveIt, YOLO/SAM/Depth/PCA 기반 perception, TaskStep Queue 기반 작업 조율을 통합해 음성/GUI 명령으로 공구 가져오기와 반납을 수행하는 로봇 어시스턴트를 개발하고, QA·트러블슈팅·시연 설계·팀 일정 관리를 담당했다.</p>
<h2 id="성과-중심-요약">성과 중심 요약</h2>
<ul>
<li>ROS 2 node/topic/service/action 구조를 기준으로 command-task-perception-manipulation-UI 패키지 책임과 통신 흐름 정리</li>
<li>TaskStep Queue를 활용해 bring/return 작업을 pause/resume/cancel/recovery 가능한 상태 기반 구조로 설계</li>
<li>VLM, Gemini API, YOLO, SAM+Depth, PCA 방식을 비교하고 실제 로봇 제어에 적합한 perception pipeline 도출</li>
<li>YOLO 평가 기준을 mAP 중심이 아닌 grasp pipeline 사용 가능성, bbox 품질, threshold/NMS 영향 중심으로 재정의</li>
<li>Depth, CameraInfo, calibration, TF 변환을 2D detection 결과와 MoveIt target pose 사이의 핵심 연결부로 정리</li>
<li>MoveIt planning scene, URDF/Xacro collision geometry, controller 연결, IK branch 문제를 QA 로그 기반으로 분석</li>
<li>structured log 통일과 QA 문서화를 통해 depth projection 실패, planning 실패, drawer collision, handoff 실패 등 원인 추적</li>
<li>발표 및 시연 시나리오를 기본 성공 흐름뿐 아니라 실패/복구 중심으로 구성해 프로젝트 강건성 강조</li>
</ul>
<h2 id="주요-기여-bullet">주요 기여 Bullet</h2>
<ul>
<li>ROS 2 기반 공구 전달 로봇 MacGyvBot에서 PM 및 통합 담당으로 일정 관리, 업무 분담, QA, 시연 시나리오 설계 수행</li>
<li>node/topic/service/action 책임 분리를 기준으로 command, task, perception, manipulation, UI 계층 간 통신 흐름과 디버깅 기준 정리</li>
<li>YOLO, VLM, SAM+Depth, PCA 기반 grasp point 및 yaw 추정 방식을 비교하고 실제 로봇 제어에 적합한 perception pipeline 선정</li>
<li>Detection 결과를 depth, CameraInfo, calibration, TF 변환을 거쳐 robot base 기준 pick pose로 연결하는 2D-to-3D perception 흐름 검증</li>
<li>TaskStep Queue 구조를 통해 bring/return 작업의 pause, resume, cancel, drop recovery 흐름을 상태 기반으로 관리</li>
<li>MoveIt planning 실패, depth projection 실패, drawer collision, wrist joint branch 문제 등 실제 로봇 테스트 이슈를 로그 기반으로 분석</li>
<li>structured log format과 패키지 책임 분리를 정리해 command, task, perception, manipulation, UI 계층 간 디버깅 효율 개선</li>
</ul>
<h2 id="면접에서-이야기할-메시지">면접에서 이야기할 메시지</h2>
<p>이 프로젝트에서 가장 크게 배운 점은 &quot;AI 모델이 잘 맞히는 것&quot;과 &quot;로봇이 실제로 안전하게 작업을 완수하는 것&quot;은 다르다는 점입니다. YOLO나 VLM이 이미지에서 결과를 내더라도, 그 결과는 아직 2D 인식 정보일 뿐입니다. 실제 로봇 작업이 되려면 depth, camera intrinsic, hand-eye calibration, TF 변환, yaw 계산, gripper width, safe workspace clamp, MoveIt planning, collision scene, controller 실행, 사용자 handoff 안전성까지 모두 맞아야 합니다.</p>
<p>그래서 저는 단순 모델 적용보다 전체 시스템에서 실패가 발생하는 지점을 나누는 데 집중했습니다. ROS 2 통신 구조로 책임을 분리하고, TaskStep Queue로 긴 작업을 상태 기반으로 관리하며, structured log와 QA 시나리오를 통해 perception, planning, manipulation, UI 문제를 구분해 개선했습니다. 이 경험을 통해 지능형 로봇 프로젝트에서는 모델 성능뿐 아니라 시스템 통합, 안전 조건, 실패 복구 설계가 실제 완성도를 결정한다는 점을 배웠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Business] 비즈니스 커뮤니케이션 이론 정리]]></title>
            <link>https://velog.io/@jack_7711/Business-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EC%BB%A4%EB%AE%A4%EB%8B%88%EC%BC%80%EC%9D%B4%EC%85%98-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Business-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EC%BB%A4%EB%AE%A4%EB%8B%88%EC%BC%80%EC%9D%B4%EC%85%98-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 19 Jun 2026 11:41:22 GMT</pubDate>
            <description><![CDATA[<h1 id="비즈니스-커뮤니케이션은-결국-사람을-이해하는-기술이다">비즈니스 커뮤니케이션은 결국 사람을 이해하는 기술이다</h1>
<p>비즈니스 커뮤니케이션을 공부하면서 가장 크게 느낀 점은, 커뮤니케이션이 단순히 말을 잘하는 기술이 아니라는 것이다. 말투, 태도, 표정, 복장, 전화 응대, 이메일 작성, 문자 한 줄까지 모두 상대에게 나를 보여주는 방식이다.</p>
<p>결국 비즈니스 커뮤니케이션의 핵심은 <strong>상대와 좋은 관계를 만들고, 신뢰를 쌓고, 상황에 맞는 방식으로 메시지를 전달하는 것</strong>이다.</p>
<p>우리가 배운 내용은 크게 다음 흐름으로 연결된다.</p>
<ol>
<li>관계의 중요성</li>
<li>소통과 갈등 이해</li>
<li>행동심리와 감정</li>
<li>기본 커뮤니케이션 표현</li>
<li>호감 가는 대화법</li>
<li>DISC 유형별 커뮤니케이션</li>
<li>인상과 이미지</li>
<li>태도와 비즈니스 매너</li>
<li>전화, 이메일, 문자·카톡 매너</li>
<li>용모와 복장</li>
<li>테이블 매너</li>
<li>AI 시대의 소통 변화</li>
</ol>
<hr>
<h2 id="1-관계는-비즈니스-커뮤니케이션의-출발점이다">1. 관계는 비즈니스 커뮤니케이션의 출발점이다</h2>
<p>비즈니스 현장에서 관계는 매우 중요하다. 사람들은 일 자체보다 함께 일하는 사람과의 관계 때문에 만족하기도 하고, 반대로 인간관계 때문에 퇴사를 고민하기도 한다.</p>
<p>좋은 관계를 만들기 위해서는 먼저 나와 상대를 바라보는 태도가 중요하다.</p>
<p>자료에서는 인간관계의 태도를 네 가지로 설명한다.</p>
<ul>
<li>나는 OK, 타인도 OK</li>
<li>나는 OK, 타인은 Not OK</li>
<li>나는 Not OK, 타인은 OK</li>
<li>나는 Not OK, 타인도 Not OK</li>
</ul>
<p>이 중 가장 바람직한 태도는 <strong>자타긍정</strong>, 즉 “나는 OK, 타인도 OK”라는 태도이다. 이 태도는 협력과 공존을 가능하게 한다.</p>
<p>반대로 타인을 무시하거나, 자신을 지나치게 낮추거나, 모두를 불신하는 태도는 건강한 관계를 어렵게 만든다.</p>
<p>결국 좋은 커뮤니케이션은 <strong>나와 상대 모두를 존중하는 태도</strong>에서 시작된다.</p>
<hr>
<h2 id="2-소통이-어려운-이유는-서로-다르기-때문이다">2. 소통이 어려운 이유는 서로 다르기 때문이다</h2>
<p>사람들은 생각하는 방식, 일하는 속도, 감정 표현, 의사결정 방식이 모두 다르다. 세대 차이도 있고, 성격 차이도 있으며, 경험과 가치관도 다르다.</p>
<p>갈등은 단순히 서로 다르기 때문에 생기는 것이 아니다. 진짜 문제는 <strong>다름을 인정하지 않거나, 내 생각만 옳다고 믿을 때</strong> 생긴다.</p>
<p>따라서 소통에서 중요한 것은 다음 세 가지이다.</p>
<ul>
<li>존중</li>
<li>배려</li>
<li>공감</li>
</ul>
<p>존중은 상대를 귀하게 여기는 태도이다.<br>배려는 상대의 입장에서 생각하는 것이다.<br>공감은 상대의 감정과 욕구를 이해하려는 노력이다.</p>
<p>소통은 말의 기술이 아니라, 상대를 받아들이는 태도에서 시작된다.</p>
<hr>
<h2 id="3-사람마다-정보를-받아들이는-방식이-다르다">3. 사람마다 정보를 받아들이는 방식이 다르다</h2>
<p>행동심리이론에서는 사람들이 정보를 받아들이는 감각 체계가 다르다고 본다.</p>
<p>대표적으로 VAKD 유형이 있다.</p>
<ul>
<li>V형: 시각형</li>
<li>A형: 청각형</li>
<li>K형: 신체감각형</li>
<li>D형: 내부언어형</li>
</ul>
<p>시각형은 그림, 표정, 이미지, 시각 자료에 민감하다.<br>청각형은 목소리, 말투, 설명 방식에 영향을 받는다.<br>신체감각형은 분위기, 체험, 느낌, 움직임을 중요하게 여긴다.<br>내부언어형은 논리, 분석, 단어, 근거를 중시한다.</p>
<p>따라서 같은 내용을 전달하더라도 상대가 어떤 방식으로 받아들이는지에 따라 표현 방식을 조절해야 한다.</p>
<p><strong>[이미지 삽입 추천: VAKD 유형별 특징 정리표]</strong></p>
<pre><code class="language-text">V 시각형: 이미지, 표정, 자료
A 청각형: 목소리, 말투, 설명
K 신체감각형: 분위기, 경험, 느낌
D 내부언어형: 논리, 분석, 근거</code></pre>
<hr>
<h2 id="4-감정은-행동을-만든다">4. 감정은 행동을 만든다</h2>
<p>사람은 어떤 자극을 받으면 감정이 생기고, 그 감정은 행동으로 이어진다.</p>
<pre><code class="language-text">자극 -&gt; 감정 -&gt; 행동</code></pre>
<p>비즈니스 현장에서 전달자는 상대에게 강력한 자극이 될 수 있다. 나의 말투, 표정, 태도, 복장, 목소리 하나가 상대의 감정을 바꿀 수 있다.</p>
<p>그래서 전달자에게는 <strong>눈치와 센스</strong>가 필요하다.</p>
<p>특히 서비스 상황에서는 정서노동도 중요하다. 정서노동은 자신의 감정을 그대로 드러내지 않고, 상황에 맞는 감정 표현을 조절하는 것이다.</p>
<p>예를 들어 속으로는 힘들어도 고객 앞에서는 차분하고 친절하게 응대해야 하는 상황이 이에 해당한다.</p>
<hr>
<h2 id="5-기본-커뮤니케이션은-말투에서-드러난다">5. 기본 커뮤니케이션은 말투에서 드러난다</h2>
<p>기본 커뮤니케이션에서 중요한 것은 호칭, 존칭, 의뢰형 표현, 긍정형 표현, 쿠션어이다.</p>
<p>상대의 이름이나 직급을 정확히 부르는 것은 존중의 표현이다.</p>
<p>또한 명령형보다 의뢰형을 사용하는 것이 좋다.</p>
<pre><code class="language-text">기다리세요.
-&gt; 잠시만 기다려 주시겠습니까?

이쪽으로 가세요.
-&gt; 이쪽으로 이동해 주시겠습니까?

다시 전화하세요.
-&gt; 확인 후 다시 연락 주시겠습니까?</code></pre>
<p>부정형 표현도 긍정형으로 바꾸는 것이 좋다.</p>
<pre><code class="language-text">모릅니다.
-&gt; 확인 후 안내드리겠습니다.

안 됩니다.
-&gt; 현재는 어렵지만, 이 방법은 가능하십니다.

못 합니다.
-&gt; 가능한 방법을 찾아보겠습니다.</code></pre>
<p>쿠션어도 대화를 부드럽게 만든다.</p>
<ul>
<li>실례합니다만</li>
<li>번거로우시겠지만</li>
<li>괜찮으시다면</li>
<li>가능하시다면</li>
<li>죄송합니다만</li>
</ul>
<p>작은 표현의 차이가 상대가 느끼는 존중의 정도를 바꾼다.</p>
<hr>
<h2 id="6-호감-가는-커뮤니케이션은-bmw로-설명된다">6. 호감 가는 커뮤니케이션은 BMW로 설명된다</h2>
<p>호감 가는 커뮤니케이션은 BMW로 설명할 수 있다.</p>
<ul>
<li>Body Language</li>
<li>Mood</li>
<li>Word</li>
</ul>
<p>Body Language는 자세, 태도, 몸짓을 의미한다.<br>Mood는 분위기, 열의, 신념, 가치관을 의미한다.<br>Word는 말의 속도, 높낮이, 강약, 언어 표현을 의미한다.</p>
<p>즉 좋은 대화는 말의 내용만으로 만들어지지 않는다. 몸짓과 분위기, 말투가 함께 맞아야 한다.</p>
<p>또한 상대와 공통점을 찾는 것도 중요하다.</p>
<pre><code class="language-text">관찰 -&gt; 공통점 단서 탐색 -&gt; 질문 -&gt; 공통점 확인 -&gt; 공통점 화제</code></pre>
<p>반대로 피해야 할 표현도 있다.</p>
<ul>
<li>항상</li>
<li>맨날</li>
<li>언제나</li>
<li>반드시</li>
<li>꼭</li>
<li>확실히</li>
</ul>
<p>이런 극단적 언어와 당위적 언어는 상대를 방어적으로 만들 수 있다.</p>
<p>호감 가는 대화는 상대의 욕구를 확인하고, 감정을 포착하고, 그 감정을 함께 나누는 데서 시작된다.</p>
<hr>
<h2 id="7-disc-유형을-알면-대화-방식이-달라진다">7. DISC 유형을 알면 대화 방식이 달라진다</h2>
<p>DISC는 사람의 행동 유형을 네 가지로 나눈다.</p>
<ul>
<li>D형: 주도형</li>
<li>I형: 사교형</li>
<li>S형: 안정형</li>
<li>C형: 신중형</li>
</ul>
<p>D형은 목표와 결과를 중시한다. 빠른 결정과 핵심적인 설명을 선호한다.<br>I형은 사람 중심이고, 인정과 칭찬을 좋아한다.<br>S형은 안정과 조화를 중시하며, 갈등을 싫어한다.<br>C형은 정확성, 근거, 논리를 중요하게 생각한다.</p>
<p>따라서 유형에 따라 대화 방식도 달라져야 한다.</p>
<pre><code class="language-text">D형: 핵심과 결과 중심으로 말하기
I형: 긍정적 분위기와 칭찬 활용하기
S형: 안정감과 충분한 설명 제공하기
C형: 자료, 근거, 논리 제시하기</code></pre>
<p>유형을 이해한다는 것은 상대를 틀에 가두는 것이 아니라, 상대가 편하게 받아들일 수 있는 방식으로 소통하려는 노력이다.</p>
<hr>
<h2 id="8-인상과-이미지는-비즈니스-신뢰를-만든다">8. 인상과 이미지는 비즈니스 신뢰를 만든다</h2>
<p>인상은 어떤 대상에 대해 마음속에 새겨지는 느낌이다. 비즈니스에서는 첫인상이 매우 중요하다.</p>
<p>첫인상은 짧은 시간 안에 형성되고, 이후 평가에도 계속 영향을 준다. 한 가지 긍정적 인상이 다른 특성까지 좋게 보이게 만드는 후광효과도 발생한다.</p>
<p>비즈니스에서 사람을 평가할 때 중요한 기준은 두 가지이다.</p>
<ul>
<li>Warmth: 신뢰와 호감</li>
<li>Competence: 능력</li>
</ul>
<p>상대는 나를 보며 동시에 두 가지를 판단한다.</p>
<pre><code class="language-text">이 사람은 믿을 수 있는가?
이 사람은 일을 잘할 수 있는가?</code></pre>
<p>따라서 성공적인 비즈니스 이미지는 단순히 멋있게 보이는 것이 아니라, <strong>신뢰감과 전문성을 함께 주는 상태</strong>이다.</p>
<hr>
<h2 id="9-태도와-매너는-기본이지만-강력하다">9. 태도와 매너는 기본이지만 강력하다</h2>
<p>비즈니스 매너는 사소해 보이지만 관계를 결정하는 중요한 요소이다.</p>
<p>인사는 첫인상을 만들고 신뢰와 친밀감을 형성한다.<br>악수는 눈을 맞추고 미소를 지으며 적당한 힘으로 하는 것이 좋다.<br>명함을 주고받을 때는 양손을 사용하고, 받은 명함을 바로 넣지 않고 확인하는 태도가 필요하다.</p>
<p>회의 매너도 중요하다.</p>
<p>회의 전에는 목적과 자료를 준비해야 한다.<br>회의 중에는 말 끊기, 감정적 표현, 불필요한 전자기기 사용을 피해야 한다.<br>회의 후에는 회의 내용을 문서화하고 후속 조치를 해야 한다.</p>
<p>출퇴근 매너 역시 직장인의 태도를 보여준다. 출근 시간은 조직과의 첫 번째 약속이고, 퇴근 전 정리와 인사는 동료의 업무 흐름을 배려하는 행동이다.</p>
<hr>
<h2 id="10-전화-매너는-목소리로-만드는-첫인상이다">10. 전화 매너는 목소리로 만드는 첫인상이다</h2>
<p>전화는 얼굴이 보이지 않는다. 그래서 목소리의 톤, 속도, 억양이 중요하다.</p>
<p>전화 응대의 특징은 다음과 같다.</p>
<ul>
<li>비언어적 요소가 제한된다</li>
<li>실시간 상호작용이 이루어진다</li>
<li>감정 전달이 민감하다</li>
<li>기록성과 책임성에 한계가 있다</li>
<li>대면과 비대면의 중간 형태이다</li>
</ul>
<p>전화를 걸 때는 자기소개, 소속, 용건을 간결하게 말해야 한다.<br>전화를 받을 때는 상대방 정보와 용건을 정확히 확인해야 한다.</p>
<p>전화 메모에는 다음 내용이 포함되어야 한다.</p>
<ul>
<li>누가 전화했는가</li>
<li>언제 전화했는가</li>
<li>연락처는 무엇인가</li>
<li>전달 사항은 무엇인가</li>
<li>처리 요청 사항은 무엇인가</li>
</ul>
<p>전화는 빠르고 직접적인 소통 도구이지만, 기록이 남지 않을 수 있기 때문에 메모와 재확인이 중요하다.</p>
<hr>
<h2 id="11-이메일은-구조가-곧-매너다">11. 이메일은 구조가 곧 매너다</h2>
<p>이메일은 공식적인 비즈니스 커뮤니케이션에서 자주 사용된다. 이메일을 잘 쓰기 위해서는 구조가 중요하다.</p>
<p>이메일의 기본 구성은 다음과 같다.</p>
<pre><code class="language-text">제목
인사말
자기소개
요약
본문
끝인사
서명
첨부파일 확인 문구</code></pre>
<p>제목은 내용을 요약하는 방식으로 작성해야 한다.</p>
<p>예를 들어 다음과 같이 쓸 수 있다.</p>
<pre><code class="language-text">[요청] 2026 상반기 마케팅 기획안 검토의 건
[비즈니스커뮤니케이션] 수업 관련 상담 요청드립니다</code></pre>
<p>수신자 설정도 중요하다.</p>
<ul>
<li>TO: 직접 처리해야 하는 사람</li>
<li>CC: 참고가 필요한 사람</li>
<li>BCC: 수신자가 드러나면 안 되는 경우</li>
</ul>
<p>첨부파일이 있을 때는 파일명을 정돈하고, 본문에서 첨부 여부를 알려야 한다.</p>
<pre><code class="language-text">비즈니스커뮤니케이션_과제_20260416.pdf</code></pre>
<p>이메일은 단순한 글이 아니라, 나의 논리성과 전문성을 보여주는 공식 문서에 가깝다.</p>
<hr>
<h2 id="12-문자와-카톡은-짧지만-더-조심해야-한다">12. 문자와 카톡은 짧지만 더 조심해야 한다</h2>
<p>문자와 카톡은 짧고 편리하지만, 오해가 생기기 쉽다. 표정과 목소리가 빠진 텍스트이기 때문이다.</p>
<p>단답형 표현은 차갑게 느껴질 수 있다.</p>
<pre><code class="language-text">네.</code></pre>
<p>보다 나은 표현은 다음과 같다.</p>
<pre><code class="language-text">확인했습니다. 감사합니다.</code></pre>
<p>업무 메시지는 한 번에 완결형으로 보내는 것이 좋다.</p>
<pre><code class="language-text">안녕하세요, 팀장님.
OO 프로젝트 기획안 검토 부탁드립니다.
주요 변경점 3가지를 아래에 정리해 드립니다.
확인 가능하실 때 검토 부탁드립니다.</code></pre>
<p>단체 채팅방은 공적인 게시판처럼 사용해야 한다. 사적인 대화, 과도한 이모티콘, 불필요한 알림은 피하는 것이 좋다.</p>
<p>퇴근 후 연락도 조심해야 한다. 상대의 휴식권을 존중해야 하기 때문이다.</p>
<p>급한 상황이라면 쿠션어를 사용해야 한다.</p>
<pre><code class="language-text">늦은 시간에 죄송합니다만, 급히 확인이 필요한 내용이 있어 연락드립니다.</code></pre>
<p>가능하다면 예약 메시지를 활용하는 것이 더 좋다.</p>
<hr>
<h2 id="13-용모와-복장은-말하기-전-전달되는-메시지다">13. 용모와 복장은 말하기 전 전달되는 메시지다</h2>
<p>용모와 복장은 비언어적 커뮤니케이션이다. 사람은 말을 하기 전에 이미 상대의 복장, 표정, 자세, 태도를 보고 판단한다.</p>
<p>복장은 단순히 꾸미는 것이 아니라, 역할 수행에 맞게 설계된 도구이다. 드레스코드는 규칙이라기보다 서로 헷갈리지 않기 위한 약속이다.</p>
<p>직장인의 복장은 TPO에 맞아야 한다.</p>
<pre><code class="language-text">Time 시간
Place 장소
Occasion 상황</code></pre>
<p>복장의 기본 원칙은 다음과 같다.</p>
<ul>
<li>단정함과 청결 유지</li>
<li>업무에 효율적인 복장 선택</li>
<li>직무와 회사 이미지 고려</li>
<li>지나치게 화려한 복장 지양</li>
<li>과도한 유행 추종 지양</li>
</ul>
<p>비즈니스 복장은 크게 세 가지로 나눌 수 있다.</p>
<ul>
<li>포멀 정장</li>
<li>비즈니스 캐주얼</li>
<li>캐주얼 또는 자율 복장</li>
</ul>
<p>첫 출근이나 면접처럼 아직 능력이 검증되지 않은 상황에서는 복장이 더 큰 영향을 준다. 이때는 회사 분위기를 파악하기 전까지 조금 더 단정하게 입는 것이 안전하다.</p>
<hr>
<h2 id="14-헤어스타일과-액세서리도-전문성을-보여준다">14. 헤어스타일과 액세서리도 전문성을 보여준다</h2>
<p>직장인의 헤어스타일은 청결하고 단정해야 한다. 앞머리가 얼굴을 가리지 않도록 하고, 과도한 탈색이나 스타일링은 피하는 것이 좋다.</p>
<p>면접에서는 특히 표정이 잘 보이는 스타일이 좋다. 눈썹과 이마가 어느 정도 보이면 더 밝고 신뢰감 있는 인상을 줄 수 있다.</p>
<p>액세서리는 복장을 완성하는 마지막 디테일이다. 하지만 과하면 전문성을 떨어뜨릴 수 있다.</p>
<p>직장에서 적절한 액세서리는 다음과 같다.</p>
<ul>
<li>심플한 시계</li>
<li>단정한 가방</li>
<li>깔끔한 구두</li>
<li>작은 귀걸이나 목걸이</li>
<li>결혼반지 또는 절제된 반지</li>
</ul>
<p>피해야 할 것은 다음과 같다.</p>
<ul>
<li>과도한 레이어드 액세서리</li>
<li>소리 나는 장신구</li>
<li>지나치게 화려한 가방</li>
<li>더러운 구두</li>
<li>너무 높은 하이힐</li>
<li>샌들, 슬리퍼</li>
</ul>
<p>작은 디테일이 전체 인상을 바꾼다.</p>
<hr>
<h2 id="15-향수와-메이크업은-상대에-대한-성의다">15. 향수와 메이크업은 상대에 대한 성의다</h2>
<p>피부, 손톱, 체취, 구강 위생, 면도, 향수, 메이크업도 비즈니스 이미지의 일부이다.</p>
<p>특히 향수는 조심해야 한다. 사무실은 밀폐된 공간이기 때문에 강한 향은 두통이나 불쾌감을 줄 수 있다.</p>
<p>향수 에티켓은 다음과 같다.</p>
<ul>
<li>출근 전에 미리 뿌리기</li>
<li>피부에 소량만 사용하기</li>
<li>맥박이 뛰는 곳에 1~2회만 사용하기</li>
<li>“맡히는 향”이 아니라 “은은히 느껴지는 향”으로 유지하기</li>
</ul>
<p>메이크업은 꾸밈이 아니라 상대에 대한 성의로 볼 수 있다. 비즈니스 환경에서는 자연스럽고 단정한 메이크업이 적절하다.</p>
<hr>
<h2 id="16-테이블-매너는-식사-자리의-커뮤니케이션이다">16. 테이블 매너는 식사 자리의 커뮤니케이션이다</h2>
<p>테이블 매너도 비즈니스 매너의 일부이다. 식사 자리에서도 사람의 태도와 배려가 드러난다.</p>
<p>냅킨은 모두가 착석한 뒤 주인을 따라 펴고, 식사 중 자리를 비울 때는 의자 위에 둔다. 식사가 끝났을 때는 테이블 위에 올려둔다.</p>
<p>나이프와 포크를 들고 말하지 않고, 떨어뜨린 식기는 직접 줍지 않고 종업원에게 새것을 요청한다.</p>
<p>양식 코스는 보통 다음 순서로 진행된다.</p>
<pre><code class="language-text">전채요리 -&gt; 수프 -&gt; 생선 -&gt; 고기 -&gt; 샐러드 -&gt; 디저트 -&gt; 음료</code></pre>
<p>빵은 배를 채우는 것이 아니라 코스 사이에 조금씩 먹는 것이다. 나이프로 자르지 않고 손으로 먹는다.</p>
<p>와인은 색, 향, 맛을 확인하며, 받을 때는 잔을 들지 않고 손만 살짝 올리는 것이 좋다.</p>
<hr>
<h2 id="17-ai-시대에는-공감-능력이-더-중요해진다">17. AI 시대에는 공감 능력이 더 중요해진다</h2>
<p>AI 시대가 되면서 소통 방식은 빠르게 변하고 있다. 하지만 기술이 발전할수록 오히려 인간적인 감성과 공감 능력은 더 중요해진다.</p>
<p>자료에서는 이를 이렇게 표현한다.</p>
<pre><code class="language-text">하이테크는 하이터치를 요구한다.</code></pre>
<p>기술이 발달할수록 사람은 더 따뜻한 반응, 세심한 배려, 진정성 있는 공감을 원한다.</p>
<p>AI가 정보를 빠르게 처리할 수는 있지만, 상대의 감정을 읽고 관계를 만드는 것은 여전히 사람의 영역이다.</p>
<hr>
<h2 id="18-비즈니스-커뮤니케이션은-하나의-흐름으로-연결된다">18. 비즈니스 커뮤니케이션은 하나의 흐름으로 연결된다</h2>
<p>지금까지 배운 내용은 따로 떨어진 개념이 아니다.</p>
<p>관계의 중요성은 소통의 태도로 연결되고, 소통의 태도는 말투와 표현으로 나타난다. 말투와 표현은 전화, 이메일, 문자, 회의, 보고, 인사, 악수 같은 실제 행동으로 이어진다. 그리고 복장, 표정, 자세, 이미지까지 함께 작용해 상대에게 나라는 사람을 전달한다.</p>
<p>전체 흐름은 다음과 같이 정리할 수 있다.</p>
<pre><code class="language-text">관계 이해
   ↓
존중과 공감
   ↓
상대 유형 파악
   ↓
상황에 맞는 표현
   ↓
전화·이메일·문자 매너
   ↓
태도·용모·복장
   ↓
신뢰와 전문성 형성</code></pre>
<p>결국 비즈니스 커뮤니케이션은 <strong>말을 잘하는 능력</strong>이 아니라, <strong>상대가 나를 신뢰할 수 있도록 모든 표현을 조율하는 능력</strong>이다.</p>
<hr>
<h2 id="19-최종-정리">19. 최종 정리</h2>
<p>비즈니스 커뮤니케이션의 핵심은 사람이다.</p>
<p>상대를 존중하고, 다름을 인정하고, 감정을 이해하며, 상황에 맞는 방식으로 표현해야 한다. 말투, 표정, 태도, 복장, 전화 한 통, 이메일 한 줄, 카톡 메시지 하나까지 모두 나의 이미지가 된다.</p>
<p>좋은 커뮤니케이션은 화려한 말솜씨가 아니라, 상대가 “이 사람은 나를 존중하고 있다”고 느끼게 만드는 것이다.</p>
<p>결국 이 수업의 내용을 한 문장으로 정리하면 다음과 같다.</p>
<blockquote>
<p>비즈니스 커뮤니케이션은 관계 속에서 신뢰와 전문성을 전달하는 모든 말과 행동의 기술이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Business] Operation Management 이론 정리]]></title>
            <link>https://velog.io/@jack_7711/Business-Operation-Management-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Business-Operation-Management-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 19 Jun 2026 07:36:32 GMT</pubDate>
            <description><![CDATA[<h1 id="operation-management는-기업의-자원을-고객가치로-바꾸는-시스템이다">Operation Management는 기업의 자원을 고객가치로 바꾸는 시스템이다</h1>
<p>생산운영관리(Operation Management, OM)를 한 학기 동안 공부하면서 가장 크게 느낀 것은, OM이 단순히 공장이나 생산라인을 관리하는 과목이 아니라는 점이다. 운영관리는 기업이 가진 사람, 자본, 설비, 원자재, 정보, 기술을 활용해 고객이 원하는 제품과 서비스를 만들어내는 전체 시스템을 설계하고 개선하는 학문이다.</p>
<p>즉, OM은 단순히 “무언가를 생산하는 방법”이 아니라, <strong>투입(input)을 산출(output)로 바꾸는 변환 과정(transformation process)을 어떻게 효율적이고 효과적으로 관리할 것인가</strong>를 다룬다.</p>
<hr>
<h2 id="1-전체-흐름으로-보는-om">1. 전체 흐름으로 보는 OM</h2>
<p>Operation Management는 투입을 산출로 바꾸는 변환 과정을 관리한다. 투입에는 사람, 자본, 설비, 원자재, 정보, 기술이 포함되고, 산출에는 제품과 서비스가 포함된다.</p>
<p>이 과정에서 기업은 비용, 품질, 납기, 유연성, 지속가능성 사이의 균형을 잡아야 한다.</p>
<p>한 학기 내용은 크게 다음 흐름으로 연결된다.</p>
<ol>
<li>OM의 기본 개념과 생산성</li>
<li>사회적 책임, 친환경 경영, ESG</li>
<li>운영전략과 프로젝트관리</li>
<li>품질경쟁력과 수요예측</li>
<li>제품 및 서비스 설계</li>
<li>프로세스 설계와 공급사슬 지속가능성</li>
<li>생산능력, 입지, 배치, 품질경영</li>
<li>공급사슬관리(SCM)</li>
<li>재고관리</li>
<li>생산계획 시스템과 MRP</li>
<li>ERP, e-Operations, 스마트공장</li>
<li>JIT, 린 생산, 프로세스 혁신</li>
<li>의사결정 도구</li>
</ol>
<p>핵심 질문은 다음과 같다.</p>
<ul>
<li>무엇을, 얼마나, 언제, 어디서, 어떻게 생산할 것인가?</li>
<li>고객이 원하는 품질과 납기를 어떻게 맞출 것인가?</li>
<li>재고를 얼마나 둘 것인가?</li>
<li>공급사슬 전체를 어떻게 연결하고 통제할 것인가?</li>
<li>디지털 기술과 데이터로 운영을 어떻게 고도화할 것인가?</li>
<li>비용 절감과 사회적 책임, 지속가능성을 어떻게 동시에 달성할 것인가?</li>
</ul>
<p><strong>[이미지 삽입 추천: OM 전체 흐름도]</strong></p>
<pre><code class="language-text">전략
 ↓
제품·서비스 설계
 ↓
프로세스 설계
 ↓
생산능력 / 입지 / 배치
 ↓
품질 / 예측
 ↓
재고 / SCM
 ↓
생산계획 / MRP
 ↓
ERP / 스마트공장
 ↓
JIT / 린 / 프로세스 혁신</code></pre>
<hr>
<h2 id="2-생산운영관리의-개요와-생산성">2. 생산운영관리의 개요와 생산성</h2>
<p>생산운영관리는 제품이나 서비스를 만드는 모든 활동을 계획, 조직, 통제, 개선하는 관리 기능이다.</p>
<p>과거에는 제조업의 생산관리 중심으로 이해되었지만, 오늘날에는 서비스업, 플랫폼 기업, 물류, 공급사슬, 디지털 운영까지 포괄한다.</p>
<hr>
<h2 id="3-생산시스템은-투입-변환-산출-피드백으로-구성된다">3. 생산시스템은 투입, 변환, 산출, 피드백으로 구성된다</h2>
<p>생산시스템은 투입, 변환, 산출, 피드백으로 구성된다.</p>
<ul>
<li>투입: 노동, 자본, 원자재, 정보, 기술, 에너지</li>
<li>변환: 가공, 조립, 운송, 저장, 서비스 제공, 정보처리</li>
<li>산출: 제품, 서비스, 고객경험, 가치</li>
<li>피드백: 품질, 비용, 납기, 고객만족, 생산성 지표</li>
</ul>
<p>즉, 운영관리는 단순히 생산 결과만 보는 것이 아니라, 투입에서 산출까지 이어지는 전체 흐름을 관리한다.</p>
<p><strong>[이미지 삽입 추천: 생산시스템 구조도]</strong></p>
<pre><code class="language-text">투입 Input
사람 · 자본 · 설비 · 원자재 · 정보 · 기술
        ↓
변환 Transformation
가공 · 조립 · 운송 · 저장 · 서비스 제공
        ↓
산출 Output
제품 · 서비스 · 고객경험 · 가치
        ↓
피드백 Feedback
품질 · 비용 · 납기 · 고객만족 · 생산성</code></pre>
<hr>
<h2 id="4-om의-10대-전략적-의사결정">4. OM의 10대 전략적 의사결정</h2>
<p>운영관리자는 다음 영역에서 의사결정을 수행한다.</p>
<ul>
<li>제품 및 서비스 설계</li>
<li>품질관리</li>
<li>프로세스 및 생산능력 설계</li>
<li>입지 선정</li>
<li>배치 설계</li>
<li>인적자원과 직무설계</li>
<li>공급사슬관리</li>
<li>재고관리</li>
<li>일정계획</li>
<li>유지보수</li>
</ul>
<p>이 의사결정들은 독립되어 있지 않다.</p>
<p>예를 들어 제품 설계가 복잡하면 공정도 복잡해지고, 재고와 품질관리 부담도 커진다. 입지 선택은 물류비, 인건비, 시장 접근성, 공급업체와의 관계에 영향을 준다.</p>
<p>따라서 OM의 의사결정은 각각 따로 보는 것이 아니라, 하나의 시스템 안에서 연결해서 이해해야 한다.</p>
<hr>
<h2 id="5-생산성과-경쟁력">5. 생산성과 경쟁력</h2>
<p>생산성은 투입 대비 산출의 비율이다.</p>
<pre><code class="language-text">생산성 = 산출량 / 투입량</code></pre>
<p>부분생산성은 노동, 자본, 원자재처럼 특정 투입요소 하나를 기준으로 측정하고, 총요소생산성은 여러 투입요소를 함께 고려한다.</p>
<p>생산성을 높이는 방법은 단순히 사람을 더 빠르게 일하게 만드는 것이 아니다. 설비 자동화, 작업 표준화, 품질 개선, 재고 감축, 정보시스템 도입, 프로세스 혁신, 공급사슬 협력 등이 모두 생산성 향상 수단이다.</p>
<hr>
<h2 id="6-사회적-책임과-친환경-경영">6. 사회적 책임과 친환경 경영</h2>
<p>현대 기업은 이윤만 추구해서는 지속가능한 경쟁력을 확보하기 어렵다.</p>
<p>사회적 책임(CSR), 공유가치창출(CSV), 환경경영, ESG는 운영관리에서도 중요한 전략 요소가 되었다.</p>
<hr>
<h2 id="7-csr과-csv">7. CSR과 CSV</h2>
<p>CSR은 기업이 경제적 책임뿐 아니라 법적, 윤리적, 자선적 책임을 수행해야 한다는 관점이다.</p>
<p>CSV는 기업이 사회문제를 해결하면서 동시에 경제적 가치를 창출해야 한다는 관점이다.</p>
<p>CSR이 “기업이 사회에 책임을 진다”는 의미라면, CSV는 “사회문제 해결을 사업모델과 연결한다”는 데 초점이 있다.</p>
<hr>
<h2 id="8-환경경영과-scem">8. 환경경영과 SCEM</h2>
<p>환경경영은 제품의 생산, 유통, 사용, 폐기 전 과정에서 환경 영향을 줄이는 관리 활동이다.</p>
<p>공급사슬환경관리(SCEM)는 친환경 관점을 공급사슬 전체로 확장한다.</p>
<p>중요한 관리 대상은 다음과 같다.</p>
<ul>
<li>에너지 사용량</li>
<li>폐기물과 배출물</li>
<li>탄소발자국</li>
<li>친환경 원자재</li>
<li>재활용과 순환경제</li>
<li>협력업체의 환경성과</li>
</ul>
<hr>
<h2 id="9-esg">9. ESG</h2>
<p>ESG는 Environment, Social, Governance의 약자다.</p>
<ul>
<li>E: 기후변화, 탄소배출, 에너지, 자원순환</li>
<li>S: 노동, 안전, 인권, 지역사회, 고객보호</li>
<li>G: 이사회, 윤리경영, 투명성, 주주권리</li>
</ul>
<p>운영관리 관점에서 ESG는 선언이 아니라 실제 프로세스 설계 문제다.</p>
<p>친환경 설비, 안전한 작업장, 투명한 공급망, 책임 있는 구매, 지속가능한 물류가 모두 ESG 실행의 일부다.</p>
<hr>
<h2 id="10-생산운영전략과-프로젝트관리">10. 생산운영전략과 프로젝트관리</h2>
<p>운영전략은 기업전략과 비즈니스전략을 실제 운영 활동으로 연결한다.</p>
<p>기업이 어떤 시장에서 어떻게 경쟁할 것인지가 정해지면, 운영은 그 전략을 비용, 품질, 유연성, 시간 측면에서 구현해야 한다.</p>
<hr>
<h2 id="11-경쟁우선순위">11. 경쟁우선순위</h2>
<p>운영전략의 대표 경쟁우선순위는 다음 네 가지다.</p>
<ul>
<li>비용: 낮은 원가, 높은 효율</li>
<li>품질: 일관성, 신뢰성, 우수한 성능</li>
<li>시간: 빠른 납기, 짧은 리드타임</li>
<li>유연성: 제품 다양성, 수량 변화 대응, 맞춤화</li>
</ul>
<p>전통적 관점에서는 이 요소들 사이에 상쇄관계가 있다고 본다. 예를 들어 비용을 낮추면 품질이나 유연성이 희생될 수 있다.</p>
<p>반면 누적역량 관점에서는 품질 개선이 비용 절감과 납기 단축의 기반이 될 수 있다고 본다.</p>
<hr>
<h2 id="12-주문자격요소와-주문획득요소">12. 주문자격요소와 주문획득요소</h2>
<p>주문자격요소(order qualifier)는 고객이 구매 후보로 고려하기 위해 최소한 충족해야 하는 조건이다.</p>
<p>주문획득요소(order winner)는 고객이 실제로 선택하게 만드는 결정적 요소다.</p>
<p>예를 들어 스마트폰 시장에서 기본 품질과 앱 생태계는 주문자격요소일 수 있고, 카메라 성능이나 가격은 주문획득요소가 될 수 있다.</p>
<hr>
<h2 id="13-프로젝트관리">13. 프로젝트관리</h2>
<p>프로젝트는 명확한 시작과 끝, 고유한 목표, 제한된 자원, 불확실성을 가진 일회성 과업이다.</p>
<p>신제품 개발, 설비 구축, 정보시스템 도입, 건설, 연구개발이 대표적이다.</p>
<p>프로젝트관리는 다음 순서로 진행된다.</p>
<ol>
<li>프로젝트 목표 정의</li>
<li>작업분류체계(WBS) 작성</li>
<li>활동 순서와 의존관계 파악</li>
<li>일정과 자원 계획</li>
<li>실행과 통제</li>
<li>평가와 종료</li>
</ol>
<hr>
<h2 id="14-pert와-cpm">14. PERT와 CPM</h2>
<p>PERT와 CPM은 프로젝트 일정관리를 위한 네트워크 기법이다.</p>
<ul>
<li>CPM: 활동시간이 비교적 확정적일 때 사용</li>
<li>PERT: 활동시간의 불확실성을 확률적으로 고려</li>
</ul>
<p>PERT의 기대시간은 다음과 같이 계산한다.</p>
<pre><code class="language-text">기대시간 te = (낙관시간 a + 4 * 최빈시간 m + 비관시간 b) / 6</code></pre>
<p>주경로(critical path)는 프로젝트 전체 완료시간을 결정하는 가장 긴 경로다.</p>
<p>주경로 위의 활동은 여유시간이 없으므로 지연되면 전체 프로젝트도 지연된다.</p>
<hr>
<h2 id="15-품질경쟁력과-예측">15. 품질경쟁력과 예측</h2>
<p>품질은 고객의 요구를 충족시키는 정도다.</p>
<p>현대의 품질관리는 검사 중심에서 전사적 품질경영으로 발전했다.</p>
<hr>
<h2 id="16-품질의-관점">16. 품질의 관점</h2>
<p>품질은 여러 관점에서 볼 수 있다.</p>
<ul>
<li>성능: 제품이나 서비스의 기본 기능</li>
<li>신뢰성: 고장 없이 작동하는 정도</li>
<li>내구성: 사용 가능 기간</li>
<li>적합성: 규격과 표준 준수</li>
<li>서비스성: 수리와 지원 용이성</li>
<li>심미성: 디자인과 감성적 만족</li>
<li>지각품질: 고객이 인식하는 브랜드 신뢰</li>
</ul>
<hr>
<h2 id="17-tqm">17. TQM</h2>
<p>TQM(Total Quality Management)은 전사적 품질경영이다.</p>
<p>품질을 품질관리부서만의 책임으로 보지 않고, 최고경영자부터 현장 작업자, 공급업체까지 모두가 참여하는 지속적 개선 활동으로 본다.</p>
<p>TQM의 핵심은 다음과 같다.</p>
<ul>
<li>고객중심</li>
<li>전원참여</li>
<li>지속적 개선</li>
<li>프로세스 중심</li>
<li>데이터 기반 의사결정</li>
<li>공급업체와의 협력</li>
</ul>
<hr>
<h2 id="18-iso-인증">18. ISO 인증</h2>
<p>ISO는 국제표준화기구가 제정한 표준이다.</p>
<ul>
<li>ISO 9000 계열: 품질경영시스템</li>
<li>ISO 14000 계열: 환경경영시스템</li>
<li>ISO 22000: 식품안전경영</li>
<li>ISO 26000: 사회적 책임</li>
</ul>
<p>ISO 인증은 품질 그 자체를 보장한다기보다, 일정한 품질을 만들어낼 수 있는 관리체계가 존재함을 보여준다.</p>
<hr>
<h2 id="19-서비스품질과-servqual">19. 서비스품질과 SERVQUAL</h2>
<p>SERVQUAL은 서비스 품질을 측정하는 대표 모형이다.</p>
<p>다섯 요소는 RATER로 기억할 수 있다.</p>
<ul>
<li>Reliability: 약속한 서비스를 정확히 수행</li>
<li>Assurance: 직원의 지식, 예의, 신뢰감</li>
<li>Tangibles: 물리적 시설, 장비, 외형</li>
<li>Empathy: 고객에 대한 배려와 개별적 관심</li>
<li>Responsiveness: 신속한 대응</li>
</ul>
<hr>
<h2 id="20-예측">20. 예측</h2>
<p>예측은 미래 수요를 추정해 생산, 재고, 인력, 구매, 설비 의사결정을 지원하는 활동이다.</p>
<p>정성적 예측은 전문가 의견, 시장조사, 델파이법처럼 판단에 의존한다. 정량적 예측은 과거 데이터를 활용한다.</p>
<p>대표적인 정량적 기법은 다음과 같다.</p>
<ul>
<li>이동평균법</li>
<li>가중이동평균법</li>
<li>지수평활법</li>
<li>추세분석</li>
<li>회귀분석</li>
</ul>
<p>예측오차는 다음 지표로 평가한다.</p>
<pre><code class="language-text">MAD = |실제값 - 예측값|의 평균
MSE = (실제값 - 예측값)^2의 평균
MAPE = |실제값 - 예측값| / 실제값 * 100의 평균</code></pre>
<p>MAD는 직관적이고, MSE는 큰 오차에 민감하며, MAPE는 비율로 표현되어 비교가 쉽다.</p>
<hr>
<h2 id="21-제품-및-서비스-설계">21. 제품 및 서비스 설계</h2>
<p>설계는 운영성과를 결정하는 출발점이다.</p>
<p>제품과 서비스가 어떻게 설계되느냐에 따라 원가, 품질, 생산속도, 유연성, 고객만족이 달라진다.</p>
<hr>
<h2 id="22-제품설계">22. 제품설계</h2>
<p>제품설계는 고객 요구를 제품의 기능, 성능, 사양, 구조로 바꾸는 과정이다.</p>
<p>좋은 설계는 고객가치와 생산가능성을 동시에 고려한다.</p>
<p>주요 개념은 다음과 같다.</p>
<ul>
<li>VOC: 고객의 소리</li>
<li>QFD: 고객 요구를 기술적 특성으로 전환</li>
<li>동시공학: 설계, 생산, 구매, 품질, 마케팅이 동시에 협력</li>
<li>가치분석: 불필요한 비용을 줄이고 기능 대비 가치를 높임</li>
<li>모듈화: 부품이나 기능을 독립 단위로 설계해 다양성과 효율을 동시에 추구</li>
<li>BOM: 제품을 구성하는 부품과 자재의 명세서</li>
</ul>
<hr>
<h2 id="23-qfd와-품질의-집">23. QFD와 품질의 집</h2>
<p>QFD(Quality Function Deployment)는 고객 요구를 제품의 기술적 특성으로 전환하는 방법이다.</p>
<p>품질의 집(House of Quality)은 고객 요구, 기술 특성, 경쟁제품 비교, 기술 특성 간 관계를 시각적으로 연결한다.</p>
<hr>
<h2 id="24-서비스-설계">24. 서비스 설계</h2>
<p>서비스는 무형성, 동시성, 이질성, 소멸성이라는 특징을 가진다.</p>
<p>따라서 서비스 설계에서는 고객 접점, 대기시간, 직원 행동, 물리적 환경, 정보 흐름을 함께 설계해야 한다.</p>
<p>서비스 청사진(service blueprint)은 고객 행동, 접점 직원 행동, 후방 지원 활동, 지원 시스템을 구분해 서비스 프로세스를 시각화하는 도구다.</p>
<hr>
<h2 id="25-프로세스-설계와-공급사슬-지속가능성">25. 프로세스 설계와 공급사슬 지속가능성</h2>
<p>프로세스 설계는 제품이나 서비스를 만들기 위해 작업 흐름, 설비, 기술, 인력, 품질수준을 결정하는 활동이다.</p>
<hr>
<h2 id="26-프로세스-유형">26. 프로세스 유형</h2>
<p>대표적인 프로세스 유형은 다음과 같다.</p>
<ul>
<li>프로젝트 프로세스: 고유하고 대규모인 산출물, 낮은 반복성</li>
<li>잡샵: 다양한 제품, 낮은 표준화, 범용설비</li>
<li>배치 프로세스: 일정 묶음 단위 생산</li>
<li>라인 프로세스: 표준화된 제품의 반복 생산</li>
<li>연속 프로세스: 석유, 화학처럼 끊임없는 대량 생산</li>
</ul>
<p>제품 다양성이 높고 생산량이 낮으면 유연한 프로세스가 필요하고, 제품 표준화가 높고 생산량이 많으면 효율적인 라인 또는 연속 프로세스가 적합하다.</p>
<hr>
<h2 id="27-생산전략">27. 생산전략</h2>
<p>생산전략은 다음과 같이 나눌 수 있다.</p>
<ul>
<li>재고생산(MTS): 수요예측에 따라 미리 생산</li>
<li>주문생산(MTO): 주문 후 생산</li>
<li>주문조립(ATO): 표준 부품을 보유하고 주문 후 조립</li>
<li>주문설계(ETO): 고객 주문에 맞춰 설계부터 수행</li>
</ul>
<hr>
<h2 id="28-지속가능한-공급사슬">28. 지속가능한 공급사슬</h2>
<p>운영활동은 조달, 생산, 물류, 사용, 회수, 폐기까지 이어진다.</p>
<p>지속가능한 운영은 제품 수명주기 전체에서 환경과 사회적 영향을 고려한다.</p>
<p>중요한 개념은 다음과 같다.</p>
<ul>
<li>탄소발자국</li>
<li>수명주기평가(LCA)</li>
<li>순환경제</li>
<li>친환경 설계</li>
<li>폐기물 감축</li>
<li>재사용, 재제조, 재활용</li>
<li>ISO 14001, ISO 50001</li>
</ul>
<hr>
<h2 id="29-생산능력-입지-배치설계-품질경영">29. 생산능력, 입지, 배치설계, 품질경영</h2>
<p>생산능력은 일정 기간 동안 시스템이 산출할 수 있는 최대 능력이다.</p>
<p>생산능력 의사결정은 장기적이고 전략적이며, 이후 비용구조와 서비스 수준을 제약한다.</p>
<hr>
<h2 id="30-생산능력계획">30. 생산능력계획</h2>
<p>생산능력이 부족하면 납기 지연과 고객불만이 발생한다. 반대로 과잉능력은 고정비 부담을 키운다.</p>
<p>생산능력계획에서는 다음을 고려한다.</p>
<ul>
<li>미래 수요</li>
<li>설비 투자비</li>
<li>규모의 경제</li>
<li>병목공정</li>
<li>인력과 기술</li>
<li>수요 변동성</li>
</ul>
<hr>
<h2 id="31-입지-선정">31. 입지 선정</h2>
<p>입지는 비용, 수익, 시장 접근성, 물류, 노동력, 규제, 공급업체 접근성에 영향을 준다.</p>
<p>제조업은 원재료, 운송비, 노동비, 공급업체 접근성이 중요하고, 서비스업은 고객 접근성, 가시성, 상권, 교통, 대기시간이 중요하다.</p>
<hr>
<h2 id="32-배치-설계">32. 배치 설계</h2>
<p>배치는 사람, 자재, 정보가 공간 안에서 어떻게 흐르는지를 결정한다.</p>
<p>대표 유형은 다음과 같다.</p>
<ul>
<li>공정별 배치: 유사 기능별 설비 배치</li>
<li>제품별 배치: 제품 흐름 순서대로 설비 배치</li>
<li>고정위치 배치: 제품은 고정, 자원이 이동</li>
<li>셀룰러 배치: 유사 제품군을 위한 셀 구성</li>
<li>서비스 배치: 고객 동선과 경험 고려</li>
</ul>
<hr>
<h2 id="33-tqm의-7가지-도구">33. TQM의 7가지 도구</h2>
<p>품질개선에 자주 쓰이는 도구는 다음과 같다.</p>
<ul>
<li>체크시트</li>
<li>히스토그램</li>
<li>파레토도</li>
<li>특성요인도</li>
<li>산점도</li>
<li>관리도</li>
<li>흐름도</li>
</ul>
<p>파레토도는 “중요한 소수와 사소한 다수”를 구분하는 데 유용하고, 특성요인도는 문제 원인을 사람, 기계, 자재, 방법, 측정, 환경 등으로 구조화하는 데 유용하다.</p>
<hr>
<h2 id="34-식스시그마와-pdca">34. 식스시그마와 PDCA</h2>
<p>식스시그마는 결함을 줄이고 프로세스 변동을 관리하는 데이터 기반 개선 방법론이다.</p>
<p>대표 절차는 DMAIC이다.</p>
<ul>
<li>Define: 문제 정의</li>
<li>Measure: 측정</li>
<li>Analyze: 분석</li>
<li>Improve: 개선</li>
<li>Control: 관리</li>
</ul>
<p>PDCA는 Plan, Do, Check, Act의 순환적 개선 절차다.</p>
<hr>
<h2 id="35-공급사슬관리-scm">35. 공급사슬관리, SCM</h2>
<p>공급사슬은 원자재 공급자부터 제조업체, 물류업체, 유통업체, 최종 고객까지 이어지는 전체 흐름이다.</p>
<p>오늘날 경쟁은 개별 기업 간 경쟁을 넘어 공급사슬 간 경쟁으로 바뀌고 있다.</p>
<hr>
<h2 id="36-scm의-목적">36. SCM의 목적</h2>
<p>SCM의 목적은 공급사슬 전체 관점에서 비용을 낮추고 서비스 수준을 높이는 것이다.</p>
<p>SCM은 다음 흐름을 통합한다.</p>
<ul>
<li>물류 흐름</li>
<li>정보 흐름</li>
<li>자금 흐름</li>
<li>수요와 공급 계획</li>
<li>구매와 공급업체 관리</li>
</ul>
<hr>
<h2 id="37-구매전략과-공급업체-관리">37. 구매전략과 공급업체 관리</h2>
<p>구매는 단순히 싸게 사는 활동이 아니라 품질, 납기, 기술력, 장기 협력관계를 관리하는 전략 기능이다.</p>
<p>중요한 의사결정은 다음과 같다.</p>
<ul>
<li>단일 공급자 vs 복수 공급자</li>
<li>장기계약 vs 단기계약</li>
<li>자체생산 vs 외주</li>
<li>글로벌 소싱 vs 현지 소싱</li>
<li>공급업체 평가와 개발</li>
</ul>
<hr>
<h2 id="38-공급사슬-리스크">38. 공급사슬 리스크</h2>
<p>글로벌 공급망은 비용 효율성을 높이지만 리스크도 커진다.</p>
<p>대표 리스크는 다음과 같다.</p>
<ul>
<li>공급 중단</li>
<li>운송 지연</li>
<li>환율 변동</li>
<li>자연재해</li>
<li>정치적 규제</li>
<li>품질 문제</li>
<li>수요 급변</li>
</ul>
<p>대응 전략은 공급처 다변화, 안전재고, 가시성 확보, 정보 공유, 리스크 모니터링, 탄력적 물류망 구축이다.</p>
<hr>
<h2 id="39-재고관리">39. 재고관리</h2>
<p>재고는 고객서비스 수준을 높이고 생산을 안정화하지만, 동시에 보관비와 자본비용을 발생시킨다.</p>
<p>재고관리는 비용과 서비스의 균형을 찾는 활동이다.</p>
<hr>
<h2 id="40-재고의-유형">40. 재고의 유형</h2>
<p>재고의 유형은 다음과 같다.</p>
<ul>
<li>원자재 재고</li>
<li>재공품 재고</li>
<li>완제품 재고</li>
<li>안전재고</li>
<li>사이클 재고</li>
<li>파이프라인 재고</li>
</ul>
<hr>
<h2 id="41-재고비용">41. 재고비용</h2>
<p>재고관리에서 고려하는 비용은 다음과 같다.</p>
<ul>
<li>주문비용 또는 준비비용</li>
<li>보유비용</li>
<li>품절비용</li>
<li>구매비용</li>
</ul>
<hr>
<h2 id="42-eoq">42. EOQ</h2>
<p>EOQ(Economic Order Quantity)는 총재고비용을 최소화하는 주문량이다.</p>
<pre><code class="language-text">EOQ = sqrt((2DS) / H)</code></pre>
<ul>
<li>D: 연간 수요량</li>
<li>S: 1회 주문비용</li>
<li>H: 단위당 연간 보유비용</li>
</ul>
<p>EOQ의 핵심은 주문비용과 보유비용의 균형이다.</p>
<p>주문량이 작으면 자주 주문해야 하므로 주문비용이 증가하고, 주문량이 크면 평균재고가 증가해 보유비용이 증가한다.</p>
<hr>
<h2 id="43-재주문점과-안전재고">43. 재주문점과 안전재고</h2>
<p>재주문점(ROP)은 새 주문을 넣어야 하는 재고수준이다.</p>
<pre><code class="language-text">ROP = 리드타임 동안의 평균수요</code></pre>
<p>수요나 리드타임이 불확실하면 안전재고를 더한다.</p>
<pre><code class="language-text">ROP = 리드타임 수요 + 안전재고</code></pre>
<hr>
<h2 id="44-abc-분석">44. ABC 분석</h2>
<p>ABC 분석은 품목을 중요도에 따라 구분해 관리 강도를 달리하는 방법이다.</p>
<ul>
<li>A품목: 품목 수는 적지만 금액 비중이 큼, 엄격 관리</li>
<li>B품목: 중간 수준 관리</li>
<li>C품목: 품목 수는 많지만 금액 비중이 작음, 단순 관리</li>
</ul>
<hr>
<h2 id="45-vmi와-cpfr">45. VMI와 CPFR</h2>
<p>VMI는 공급업체가 고객사의 재고를 대신 관리하는 방식이다.</p>
<p>CPFR은 공급업체와 고객업체가 공동으로 계획, 예측, 보충을 수행하는 협력적 재고관리 방식이다.</p>
<hr>
<h2 id="46-생산계획-시스템과-mrp">46. 생산계획 시스템과 MRP</h2>
<p>생산계획은 장기, 중기, 단기 계획이 연결된 체계다.</p>
<ul>
<li>장기: 생산능력계획, 설비, 입지, 주요 프로세스</li>
<li>중기: 총괄계획, 인력, 재고, 하청, 생산율</li>
<li>단기: MPS, MRP, 작업일정계획</li>
</ul>
<hr>
<h2 id="47-총괄계획">47. 총괄계획</h2>
<p>총괄계획은 제품군 단위로 수요를 충족하기 위해 생산율, 고용수준, 재고수준, 하청 등을 조정하는 중기 계획이다.</p>
<p>대표 전략은 다음과 같다.</p>
<ul>
<li>추종전략: 수요 변화에 맞춰 생산능력 조정</li>
<li>평준화전략: 일정한 생산율 유지, 재고로 대응</li>
<li>혼합전략: 여러 수단을 결합</li>
</ul>
<hr>
<h2 id="48-mps">48. MPS</h2>
<p>MPS(Master Production Schedule)는 최종품목별로 언제, 얼마나 생산할지를 정한 단기 생산계획이다.</p>
<p>MPS는 고객주문, 수요예측, 기초재고, 생산능력, 리드타임을 고려한다. 시간구역(time fence)을 두어 가까운 기간은 변경을 제한하고 먼 기간은 유연하게 조정한다.</p>
<p>ATP(Available-to-Promise)는 고객에게 납품 약속할 수 있는 수량이다.</p>
<pre><code class="language-text">ATP = MPS 수량 - 다음 MPS 전까지 확정된 고객주문량
첫 기간 ATP = 기초재고 + MPS 수량 - 다음 MPS 전까지 확정된 고객주문량</code></pre>
<hr>
<h2 id="49-mrp">49. MRP</h2>
<p>MRP(Material Requirements Planning)는 최종품목의 생산계획을 바탕으로 하위 부품과 원자재가 언제 얼마나 필요한지 계산하는 시스템이다.</p>
<p>MRP의 주요 입력은 다음 세 가지다.</p>
<ul>
<li>MPS: 최종품목 생산계획</li>
<li>BOM: 제품 구성 정보</li>
<li>재고기록파일: 현재고, 예정입고, 리드타임, 로트크기</li>
</ul>
<p>MRP의 주요 출력은 다음과 같다.</p>
<ul>
<li>계획된 주문일정</li>
<li>계획된 주문변경</li>
<li>예외보고서</li>
<li>성과보고서</li>
<li>계획수립보고서</li>
</ul>
<p>MRP는 독립수요가 아니라 종속수요 품목에 적합하다. 완제품 수요가 정해지면 부품 수요는 BOM을 통해 계산될 수 있기 때문이다.</p>
<p><strong>[이미지 삽입 추천: MPS와 MRP 관계도]</strong></p>
<pre><code class="language-text">수요예측 / 고객주문
        ↓
MPS
최종품목을 언제, 얼마나 생산할지 결정
        ↓
BOM + 재고기록파일
        ↓
MRP
부품과 원자재를 언제, 얼마나 주문할지 계산
        ↓
계획된 주문일정 / 주문변경 / 예외보고서</code></pre>
<hr>
<h2 id="50-erp-e-operations-스마트공장">50. ERP, e-Operations, 스마트공장</h2>
<p>ERP는 기업의 생산, 구매, 재고, 물류, 회계, 인사, 영업, 고객관리 등을 공통 데이터베이스로 통합하는 정보시스템이다.</p>
<hr>
<h2 id="51-mrp에서-erp로">51. MRP에서 ERP로</h2>
<p>발전 흐름은 다음과 같다.</p>
<ol>
<li>MRP: 자재소요계획</li>
<li>폐쇄형 MRP: 실행 결과 피드백 반영</li>
<li>MRP II: 제조자원계획, 생산능력과 재무 영역까지 확장</li>
<li>ERP: 전사 자원과 업무 프로세스 통합</li>
</ol>
<hr>
<h2 id="52-erp의-특징">52. ERP의 특징</h2>
<p>ERP의 특징은 다음과 같다.</p>
<ul>
<li>중앙 데이터베이스</li>
<li>업무 프로세스 표준화</li>
<li>부서 간 정보 공유</li>
<li>실시간 의사결정 지원</li>
<li>중복 입력과 정보 불일치 감소</li>
</ul>
<p>ERP 도입은 단순한 소프트웨어 설치가 아니다.</p>
<p>기존 업무방식(as-is)을 분석하고, 바람직한 미래 프로세스(to-be)를 설계하며, 조직 변화관리와 교육을 병행해야 한다.</p>
<hr>
<h2 id="53-mes와-스마트공장">53. MES와 스마트공장</h2>
<p>ERP가 계획 계층을 담당한다면 MES(Manufacturing Execution System)는 현장 실행 계층을 담당한다.</p>
<p>스마트공장은 IoT, 센서, 빅데이터, AI, 로봇, 클라우드, CPS 등을 활용해 실시간 연결과 자동화를 구현한다.</p>
<p>스마트공장의 효과는 다음과 같다.</p>
<ul>
<li>실시간 모니터링</li>
<li>품질 이상 조기 감지</li>
<li>설비 예지보전</li>
<li>생산계획 자동 조정</li>
<li>재고와 물류 가시성 향상</li>
<li>유연생산과 맞춤생산</li>
</ul>
<hr>
<h2 id="54-초일류-오퍼레이션-프로세스-혁신">54. 초일류 오퍼레이션 프로세스 혁신</h2>
<p>초일류 오퍼레이션은 낮은 비용, 높은 품질, 빠른 납기, 높은 유연성을 동시에 추구한다.</p>
<p>이를 위해 JIT, 린 생산, 프로세스 혁신이 중요하다.</p>
<p><strong>[이미지 삽입 추천: JIT·린 생산·식스시그마 비교표]</strong></p>
<table>
<thead>
<tr>
<th>구분</th>
<th>핵심 초점</th>
<th>주요 목적</th>
</tr>
</thead>
<tbody><tr>
<td>JIT</td>
<td>필요한 것을 필요한 때 필요한 만큼</td>
<td>재고와 대기 감소</td>
</tr>
<tr>
<td>린 생산</td>
<td>고객가치 없는 낭비 제거</td>
<td>전체 흐름 개선</td>
</tr>
<tr>
<td>식스시그마</td>
<td>결함과 변동 감소</td>
<td>품질 안정화</td>
</tr>
</tbody></table>
<hr>
<h2 id="55-jit">55. JIT</h2>
<p>JIT(Just-in-Time)는 필요한 것을 필요한 때에 필요한 만큼 생산하는 시스템이다.</p>
<p>단순히 재고를 줄이는 기법이 아니라 낭비를 제거하고 흐름을 개선하는 운영철학이다.</p>
<p>JIT의 핵심 구성요소는 다음과 같다.</p>
<ul>
<li>초점화공장</li>
<li>셋업시간 단축</li>
<li>작은 로트 크기</li>
<li>균일한 작업부하</li>
<li>TPM</li>
<li>다기능작업자</li>
<li>칸반시스템</li>
<li>JIT 구매</li>
<li>품질분임조</li>
<li>공급업체와 장기 협력</li>
</ul>
<hr>
<h2 id="56-린-생산">56. 린 생산</h2>
<p>린 생산은 고객가치를 만들지 않는 모든 낭비를 제거하는 방식이다.</p>
<p>낭비에는 과잉생산, 대기, 운송, 과잉가공, 재고, 불필요한 동작, 결함이 포함된다.</p>
<p>린의 목표는 흐름을 빠르게 만들고 문제를 숨기지 않게 만드는 것이다. 재고는 문제를 가리는 완충재가 될 수 있으므로, 재고 감축은 품질문제와 공정문제를 드러내고 개선하게 만든다.</p>
<hr>
<h2 id="57-서비스와-관리부문에서의-jit">57. 서비스와 관리부문에서의 JIT</h2>
<p>JIT는 제조업뿐 아니라 서비스와 관리업무에도 적용된다.</p>
<p>예를 들어 병원의 예약과 동선 개선, 사무업무의 승인단계 축소, 콜센터의 대기시간 관리, 호텔의 객실 준비 프로세스 개선도 JIT적 사고와 연결된다.</p>
<hr>
<h2 id="58-의사결정-도구">58. 의사결정 도구</h2>
<p>운영관리자는 불확실성 속에서 의사결정을 해야 한다.</p>
<p>의사결정 도구는 대안을 구조화하고, 결과와 확률을 비교해 더 합리적인 선택을 돕는다.</p>
<hr>
<h2 id="59-의사결정-환경">59. 의사결정 환경</h2>
<p>의사결정 환경은 다음과 같이 나눌 수 있다.</p>
<ul>
<li>확실성하 의사결정: 결과를 확실히 아는 경우</li>
<li>위험하 의사결정: 결과별 확률을 아는 경우</li>
<li>불확실성하 의사결정: 확률을 모르는 경우</li>
</ul>
<hr>
<h2 id="60-의사결정-기준">60. 의사결정 기준</h2>
<p>불확실성하에서는 다음 기준을 사용할 수 있다.</p>
<ul>
<li>낙관적 기준: 각 대안의 최대 성과 중 최고 선택</li>
<li>비관적 기준: 각 대안의 최악 성과 중 최고 선택</li>
<li>후회최소화 기준: 최대 후회를 최소화</li>
<li>동등확률 기준: 모든 상태의 확률을 동일하게 가정</li>
</ul>
<hr>
<h2 id="61-emv">61. EMV</h2>
<p>위험하 의사결정에서는 기대화폐가치(EMV)를 계산한다.</p>
<pre><code class="language-text">EMV = Σ(상태별 확률 * 상태별 성과)</code></pre>
<p>EMV가 가장 높은 대안을 선택하는 것이 일반적이다.</p>
<p>단, 위험회피 성향, 자금 여력, 전략적 의미도 함께 고려해야 한다.</p>
<hr>
<h2 id="62-의사결정나무">62. 의사결정나무</h2>
<p>의사결정나무는 의사결정점, 확률사건, 결과를 나무 구조로 표현한다.</p>
<p>오른쪽에서 왼쪽으로 기대값을 계산해 최적 대안을 선택한다.</p>
<p>완전정보의 기대가치(EVPI)는 완벽한 정보를 얻기 위해 최대 얼마까지 지불할 수 있는지를 보여준다.</p>
<hr>
<h2 id="63-om-개념은-하나의-흐름으로-연결된다">63. OM 개념은 하나의 흐름으로 연결된다</h2>
<p>OM은 개별 개념을 따로 외우는 과목이 아니라 서로 연결해서 이해해야 한다.</p>
<p>예를 들어 수요예측이 부정확하면 재고관리와 생산계획이 흔들린다. 재고가 많으면 서비스 수준은 올라갈 수 있지만 보유비용이 증가하고, JIT와 린 생산의 관점에서는 낭비가 된다.</p>
<p>MPS와 MRP는 생산계획을 구체적인 자재계획으로 연결하고, ERP는 이 정보를 전사적으로 통합한다. SCM은 기업 내부를 넘어 공급업체와 고객까지 연결한다. ESG와 지속가능성은 이러한 운영 전 과정에서 환경과 사회적 책임을 고려하게 만든다.</p>
<p>따라서 전체 구조는 다음과 같이 기억할 수 있다.</p>
<pre><code class="language-text">전략 -&gt; 설계 -&gt; 프로세스 -&gt; 생산능력/입지/배치 -&gt; 품질/예측
     -&gt; 재고/SCM -&gt; 생산계획/MRP -&gt; ERP/스마트공장 -&gt; 혁신/JIT/린</code></pre>
<hr>
<h2 id="64-최종-요약">64. 최종 요약</h2>
<p>Operation Management는 기업이 고객가치를 만들기 위해 자원, 프로세스, 사람, 기술, 공급사슬을 어떻게 설계하고 운영할 것인가를 다루는 학문이다.</p>
<p>이 과목의 핵심은 효율성과 효과성의 균형이다. 비용을 낮추면서도 품질을 높이고, 납기를 단축하면서도 유연성을 확보하며, 기업성과를 추구하면서도 사회적 책임과 지속가능성을 고려해야 한다.</p>
<p>한 학기 동안 배운 내용은 결국 하나의 문장으로 정리할 수 있다.</p>
<blockquote>
<p>좋은 운영관리는 전략을 실제 프로세스로 바꾸고, 그 프로세스를 데이터와 사람, 기술, 공급사슬을 통해 지속적으로 개선하는 일이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Business] 마케팅 이론 정리]]></title>
            <link>https://velog.io/@jack_7711/Business-%EB%A7%88%EC%BC%80%ED%8C%85-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Business-%EB%A7%88%EC%BC%80%ED%8C%85-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 19 Jun 2026 06:29:02 GMT</pubDate>
            <description><![CDATA[<h1 id="마케팅은-제품을-파는-기술이-아니라-소비자의-인식을-설계하는-기술이다">마케팅은 제품을 파는 기술이 아니라, 소비자의 인식을 설계하는 기술이다</h1>
<p>마케팅을 한 학기 동안 공부하면서 가장 크게 느낀 것은, 마케팅이 단순히 “물건을 잘 파는 방법”이 아니라는 점이다. 마케팅은 제품 자체를 설명하는 일이 아니라, 소비자가 그 제품을 어떻게 인식하게 만들 것인가를 설계하는 일에 가깝다. 즉, 제품의 기능, 가격, 디자인, 브랜드명, 포장, 광고, 스토리, 감각적 경험, 사회적 의미를 모두 연결해서 소비자에게 “왜 이 제품을 사야 하는가”를 제시하는 과정이다.</p>
<p>이 관점에서 보면 마케팅의 핵심은 <strong>컨셉</strong>이다. 컨셉은 단순한 아이디어나 문구가 아니다. 컨셉은 소비자에게 제품을 사야 할 이유를 제시하고, 그 이유를 통해 구매동기를 자극하는 것이다.</p>
<p>정리하면 다음과 같다.</p>
<blockquote>
<p><strong>컨셉 = 소비자에게 제시되는 ‘사야 할 이유’</strong>
<strong>컨셉 = 의미와 가치</strong>
<strong>컨셉 = 제품이나 서비스가 소비자에게 제공하는 차별화된 가치</strong></p>
</blockquote>
<p>소비자는 제품이나 서비스에 기계적으로 반응하지 않는다. 소비자는 컨셉에 끌려 구매한다. 따라서 마케팅에서 중요한 것은 물리적 제품 자체만이 아니라, 그 제품이 어떤 의미로 인식되는가이다.</p>
<hr>
<h2 id="1-구매는-동기에서-시작되고-인식을-거쳐-행동으로-이어진다">1. 구매는 동기에서 시작되고, 인식을 거쳐 행동으로 이어진다</h2>
<p>쇼펜하우어는 “인간의 행동에 이유, 즉 동기가 없는 행동은 없다”고 보았다. 인간 세계에서 동기와 행동을 매개하는 것이 바로 <strong>인식</strong>이다.</p>
<p>이를 마케팅에 적용하면 다음과 같은 구조가 된다.</p>
<blockquote>
<p><strong>동기 → 인식 → 행동</strong>
<strong>구매동기 → 소비자 인식 → 구매행동</strong></p>
</blockquote>
<p>소비자는 단순히 제품을 보고 사는 것이 아니다. 먼저 어떤 필요나 욕망이 생기고, 그 욕망이 제품에 대한 인식으로 연결되며, 그 인식이 구매행동으로 이어진다.</p>
<p>따라서 마케팅은 소비자의 구매동기를 직접 자극하는 것이 아니라, 소비자의 인식을 설계함으로써 구매동기를 구매행동으로 이어지게 만드는 과정이다.</p>
<hr>
<h2 id="2-소비자-인식은-브랜드-이미지다">2. 소비자 인식은 브랜드 이미지다</h2>
<p>마케팅에서 소비자 인식은 브랜드 이미지와 연결된다. 브랜드 이미지는 단순히 로고나 이름이 아니다. 소비자가 제품과 브랜드에 대해 갖는 전체적인 인식이다.</p>
<p>정리하면 다음과 같다.</p>
<blockquote>
<p><strong>소비자 인식 = 브랜드 이미지</strong>
<strong>브랜드 이미지 = 개념 + 감각</strong>
<strong>브랜드 이미지 = 구매동기 + 물리적 제품에 대한 경험</strong>
<strong>브랜드 이미지 = 컨셉 + 물리적 제품에 대한 경험</strong>
<strong>브랜드 이미지 = 컨셉 + 브랜드에 대한 감각적 경험</strong></p>
</blockquote>
<p>여기서 중요한 점은 브랜드 이미지가 두 가지 요소로 구성된다는 것이다.</p>
<p>첫째, <strong>개념</strong>이다. 개념은 제품이 무엇을 의미하는지, 어떤 가치를 제공하는지, 왜 필요한지를 설명한다. 예를 들어 “프리미엄”, “편리함”, “건강함”, “젊음”, “친환경” 같은 것이 개념에 해당한다.</p>
<p>둘째, <strong>감각</strong>이다. 감각은 소비자가 브랜드를 보고, 듣고, 만지고, 사용하는 과정에서 느끼는 경험이다. 색상, 디자인, 포장, 매장 분위기, 광고 이미지, 제품 질감, 소리, 향기 등이 여기에 포함된다.</p>
<p>결국 브랜드 이미지는 머리로 이해되는 개념과 몸으로 느껴지는 감각이 결합된 결과다.</p>
<hr>
<h2 id="3-컨셉은-개념과-감각을-하나로-묶는-힘이다">3. 컨셉은 개념과 감각을 하나로 묶는 힘이다</h2>
<p>컨셉의 어원을 보면, concept는 “여럿을 붙잡아 하나로 묶는 것”이라는 의미를 갖는다. 즉, 컨셉은 흩어져 있는 여러 요소를 하나의 의미 구조로 통합하는 힘이다.</p>
<blockquote>
<p><strong>Concept = Con + Cept</strong>
<strong>Con = 함께, 같이, 묶는 것</strong>
<strong>Cept = 잡는 것, 취하는 것</strong>
<strong>Concept = 여럿을 붙잡아 하나로 묶은 것</strong></p>
</blockquote>
<p>마케팅에서 컨셉이 중요한 이유는 제품의 기능, 디자인, 가격, 포장, 브랜드명, 광고, 사용경험, 스토리 등을 하나의 방향으로 통합해야 하기 때문이다. 소비자가 어떤 브랜드를 볼 때 여러 요소가 서로 따로 놀면 인식이 분산된다. 반대로 모든 요소가 하나의 컨셉으로 일관되게 묶이면 소비자는 그 브랜드를 더 쉽게 이해하고 기억한다.</p>
<p>그래서 컨셉에는 <strong>일관성</strong>이 필요하다.</p>
<p>컨셉의 일관성은 크게 두 가지로 볼 수 있다.</p>
<p>첫째는 <strong>시간적 일관성</strong>이다. 하나의 브랜드 이미지가 자리 잡으려면 오랜 시간 동안 컨셉이 유지되어야 한다. 브랜드가 계속 다른 말을 하면 소비자는 그 브랜드가 무엇을 의미하는지 알기 어렵다.</p>
<p>둘째는 <strong>공간적 일관성</strong>이다. 제품 구성요소 간에 통일성과 일치성이 있어야 한다. 제품명, 디자인, 포장, 광고, 매장 분위기, 가격, 서비스가 서로 다른 방향을 말하면 컨셉은 약해진다.</p>
<p>결국 좋은 컨셉은 제품 전체를 하나의 의미로 묶는다.</p>
<hr>
<h2 id="4-컨셉은-개념적-사고에서-나온다">4. 컨셉은 개념적 사고에서 나온다</h2>
<p>컨셉을 잘 만들기 위해서는 개념적 사고가 필요하다. 개념적 사고는 여러 요소를 따로 보는 것이 아니라, 본질을 파악하고 통합하는 사고다.</p>
<p>자료에서는 관리자의 역량을 세 가지로 나누어 설명한다.</p>
<blockquote>
<p><strong>Technical Skill</strong>: 실행 능력
<strong>Human Skill</strong>: 사람을 다루고 협력하는 능력
<strong>Conceptual Skill</strong>: 현재의 여러 기능을 하나로 파악하고 묶는 능력</p>
</blockquote>
<p>컨셉을 만드는 사람에게 특히 중요한 것은 conceptual skill이다. 제품의 세부 기능만 잘 아는 것만으로는 충분하지 않다. 제품, 소비자, 경쟁사, 시장, 브랜드, 감각, 언어, 가격, 유통을 하나의 구조로 통합해서 볼 수 있어야 한다.</p>
<p>개념적 사고는 본질 파악과 통합이다. 개념적 사고를 하는 사람은 잡다한 것에 매몰되지 않고, 본질을 붙잡고 일을 함으로써 짧은 시간에 효율적으로 일할 수 있다.</p>
<hr>
<h2 id="5-개념은-관계-속에서-의미를-가진다">5. 개념은 관계 속에서 의미를 가진다</h2>
<p>비고츠키의 관점에서 개념은 혼자 존재하는 것이 아니라, 다른 개념들과의 관계 속에서 존재한다. 한 개념은 개념 간의 연계와 관계망 안에서 의미를 가진다.</p>
<p>개념은 크게 <strong>일상적 개념</strong>과 <strong>과학적 개념</strong>으로 나눌 수 있다.</p>
<p>일상적 개념은 경험 기반의 개념이다. 산, 물, 음식처럼 삶에서 직접 경험하면서 형성된다. 그러나 일상적 개념은 비의식적이고 자발적이며, 설명하기 어려운 경우가 많다. 구체에서 추상으로 올라가는 성격을 가진다.</p>
<p>반면 과학적 개념은 의식적이고 반성적이며, 언어적 정의를 통해 구성된다. 대상, 원리, 논리, 관계망을 통해 형성되며, 추상에서 구체로 내려오는 성격을 가진다.</p>
<p>마케팅에서 컨셉은 이 두 가지 개념을 모두 사용한다. 소비자가 일상에서 느끼는 감각과 경험을 붙잡아야 하지만, 동시에 그것을 명확한 언어와 전략으로 정리해야 한다.</p>
<hr>
<h2 id="6-가치란-교환가치와-사용가치의-결합이다">6. 가치란 교환가치와 사용가치의 결합이다</h2>
<p>마케팅에서 소비자가 제품을 구매하는 이유는 가치 때문이다. 그런데 가치는 단순하지 않다. 가치에는 두 가지 양면성이 있다.</p>
<blockquote>
<p><strong>가치 = 교환가치 + 사용가치</strong>
<strong>교환가치 = 경쟁 제품과의 차별화</strong>
<strong>사용가치 = 제품을 사용해보고 느끼는 필요성</strong></p>
</blockquote>
<p>소비자가 어떤 제품을 산다는 것은 단순히 제품을 소유하는 것이 아니다. 소비자는 그 제품이 경쟁 제품과 어떻게 다른지, 그리고 실제로 사용했을 때 어떤 필요를 충족하는지를 함께 판단한다.</p>
<p>따라서 성공한 차별화 컨셉은 다음 구조를 가져야 한다.</p>
<blockquote>
<p><strong>고객의 니즈 → 차별화된 니즈</strong>
<strong>필요성 → 차별성 → 유형성</strong></p>
</blockquote>
<p>컨셉은 필요성과 차별성을 언어로 이해시키고, 감각으로 느끼게 해야 한다. 소비자가 언어를 통해 컨셉의 필요성과 차별성을 이해하고, 감각을 통해 그것을 체감할 때 소비자 인식이 형성된다.</p>
<p>즉,</p>
<blockquote>
<p><strong>언어 + 감각 = 소비자 인식</strong></p>
</blockquote>
<hr>
<h2 id="7-가격-대비-가치는-컨셉의-힘을-결정한다">7. 가격 대비 가치는 컨셉의 힘을 결정한다</h2>
<p>소비자가 제품을 평가할 때 중요한 것은 가격 자체가 아니라 <strong>가격 대비 가치</strong>다.</p>
<p>자료에서는 가격 대비 가치를 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>가격 대비 가치 = 차별성 × 필요성 × 유형성 / 가격</strong></p>
</blockquote>
<p>여기서 차별성은 “왜 이 제품이어야 하는가”이고, 필요성은 “왜 필요한가”이며, 유형성은 “그 차별성과 필요성을 얼마나 눈에 보이게 제시했는가”이다.</p>
<p>나중에는 이 구조가 더 확장된다.</p>
<blockquote>
<p><strong>가격 대비 가치 = 차별성 × 사용혜택 × 유형성 / 사용비용 × 가격</strong>
여기에 거래비용, 거래편리성, 접근성까지 고려된다.</p>
</blockquote>
<p>즉, 소비자가 느끼는 가치는 단순히 제품의 품질만으로 결정되지 않는다. 제품을 찾고, 비교하고, 구매하고, 사용하는 데 드는 시간과 노력도 가치 판단에 포함된다.</p>
<p>그래서 구매 촉진 요인은 다음과 같이 정리할 수 있다.</p>
<blockquote>
<p><strong>구매 촉진 요인 = 차별성 × 필요성 × 유형성</strong>
<strong>구매 장애 요인 = 가격 × 비용 × 거래비용</strong></p>
</blockquote>
<p>좋은 마케팅은 구매 촉진 요인을 높이고, 구매 장애 요인을 낮춘다. 가격을 무조건 낮추는 것이 아니라, 소비자가 느끼는 가치를 높이는 것이 핵심이다.</p>
<p>기업의 생존 공식도 이와 연결된다.</p>
<blockquote>
<p><strong>가치 &gt; 가격 &gt; 원가</strong></p>
</blockquote>
<p>소비자 입장에서는 가치가 가격보다 높아야 구매한다. 생산자 입장에서는 가격이 원가보다 높아야 생존한다. 따라서 소비자와 기업이 모두 이익을 얻으려면 가치, 가격, 원가의 구조가 균형을 이루어야 한다.</p>
<hr>
<h2 id="8-좋은-컨셉은-소비자에게-이익을-너무-많이-빼앗지-않는다">8. 좋은 컨셉은 소비자에게 이익을 너무 많이 빼앗지 않는다</h2>
<p>기업이 소비자에게서 이익을 지나치게 많이 취하면 고객은 도망가고, 이익을 너무 적게 취하면 고객은 찾아오지만 기업이 유지되기 어렵다. 따라서 핵심은 고객에게 <strong>가격 대비 가치</strong>를 높여주는 것이다.</p>
<p>가격 대비 가치가 높다는 것은 소비자 입장에서 다음을 의미한다.</p>
<blockquote>
<p>“내가 지불한 돈보다 더 큰 가치를 얻었다.”</p>
</blockquote>
<p>이때 소비자는 만족하고, 반복 구매할 가능성이 높아진다. 반대로 소비자가 가격에 비해 얻는 가치가 낮다고 느끼면, 아무리 광고를 많이 해도 장기적으로 브랜드는 유지되기 어렵다.</p>
<hr>
<h2 id="9-칸트의-인식론으로-보면-컨셉은-감각을-인식으로-완성하는-형식이다">9. 칸트의 인식론으로 보면, 컨셉은 감각을 인식으로 완성하는 형식이다</h2>
<p>마케팅 수업 내용에서 중요한 부분은 칸트의 인식론과 컨셉을 연결한 것이다.</p>
<p>칸트의 관점에서 인식은 감각만으로 완성되지 않는다. 인간은 감각의 내용을 그대로 받아들이는 것이 아니라, 선천적 인식 기능을 통해 감각을 일정한 형식으로 조직한다.</p>
<p>정리하면 다음과 같다.</p>
<blockquote>
<p><strong>인식 = 감각적 경험 + 범주/개념</strong>
<strong>형식 = 감성 + 지성</strong>
<strong>감성 = 시간과 공간</strong>
<strong>지성 = 개념, 범주</strong></p>
</blockquote>
<p>자료에서는 이를 이렇게 연결한다.</p>
<blockquote>
<p><strong>감각 → 직관 → 개념 → 인식</strong></p>
</blockquote>
<p>컨셉은 감각적 경험을 흩어지게 두지 않고 붙잡아주는 형식이다. 감각은 인식의 내용이고, 컨셉은 그 내용을 특정한 의미로 찍어내는 형식이다.</p>
<p>그래서 칸트의 유명한 문장은 마케팅에도 그대로 적용된다.</p>
<blockquote>
<p><strong>감각이 없는 개념은 공허하고, 개념이 없는 감각은 맹목적이다.</strong></p>
</blockquote>
<p>마케팅 이론도 마찬가지다. 실무자와 학계가 함께 가야 한다. 실무 없는 이론은 공허하고, 이론 없는 실무는 방향을 잃기 쉽다.</p>
<p>제품도 마찬가지다. 감각적 경험만 있고 개념이 없으면 소비자는 그것이 무엇을 의미하는지 모른다. 반대로 개념만 있고 감각적 경험이 없으면 소비자는 그것을 실제로 느끼지 못한다.</p>
<hr>
<h2 id="10-브랜드-컨셉은-제품-컨셉보다-더-고차원적이다">10. 브랜드 컨셉은 제품 컨셉보다 더 고차원적이다</h2>
<p>제품 컨셉은 물리적 제품이 어떤 기능과 속성을 갖는지에 가깝다. 반면 브랜드 컨셉은 소비자가 그 제품을 어떤 상징적 의미로 이해하는지를 포함한다.</p>
<blockquote>
<p><strong>브랜드 이미지 = 제품에 대한 경험 + 브랜드 컨셉</strong></p>
</blockquote>
<p>브랜드 컨셉은 제품 컨셉을 소비자가 이해할 수 있는 사실적·상징적 언어로 표현한 것이다. 따라서 브랜드 컨셉은 제품 컨셉보다 더 고차원적인 개념이다.</p>
<p>제품 컨셉이 “이 제품은 무엇인가”를 설명한다면, 브랜드 컨셉은 “이 제품은 소비자에게 어떤 의미인가”를 설명한다.</p>
<hr>
<h2 id="11-훔볼트의-언어관-언어는-인식을-가능하게-하는-선험적-능력이다">11. 훔볼트의 언어관: 언어는 인식을 가능하게 하는 선험적 능력이다</h2>
<p>마케팅에서 언어는 단순히 설명하는 도구가 아니다. 언어는 소비자가 세계를 인식하는 방식 자체에 영향을 준다.</p>
<p>훔볼트는 언어를 인식을 가능하게 하는 선험적 능력으로 보았다. 칸트가 형식과 범주를 통해 인간 인식을 설명했다면, 훔볼트는 언어가 현실을 인식하게 만드는 틀이라고 보았다.</p>
<blockquote>
<p><strong>언어는 인간이 세계를 인식하는 도구다.</strong>
<strong>우리는 언어가 우리에게 보여주는 대로 현실을 인식한다.</strong></p>
</blockquote>
<p>예를 들어 무지개는 연속적인 색의 변화지만, “일곱 무지개”라는 언어 때문에 우리는 무지개를 일곱 색으로 인식한다. 언어가 감각 경험을 자르는 방식이 인식에 영향을 주는 것이다.</p>
<p>따라서 언어와 감각은 서로 분리되지 않는다. 언어는 감각 경험 자체에 영향을 준다. 언어는 현실을 지시하기도 하지만, 현실을 상징하고 구성하기도 한다.</p>
<p>그래서 마케팅에서는 언어 선택이 매우 중요하다. 제품명, 브랜드명, 슬로건, 카피, 설명 문구는 소비자의 인식 틀을 바꿀 수 있다.</p>
<hr>
<h2 id="12-우리의-인식은-언어-구속적이다">12. 우리의 인식은 언어 구속적이다</h2>
<p>자료에서는 “우리의 인식은 언어 구속적이다”라고 정리한다. 이는 우리가 현실을 있는 그대로 보는 것이 아니라, 언어를 통해 구성된 방식으로 본다는 의미다.</p>
<p>언어는 두 가지 방식으로 작동한다.</p>
<p>첫째, <strong>지시하는 언어</strong>다. 이는 투명한 그릇처럼 대상을 직접 가리킨다. 제품명, 상품명처럼 형태에 따라 대상을 떠올리게 하는 언어가 여기에 해당한다.</p>
<p>둘째, <strong>상징하는 언어</strong>다. 이는 색깔 있는 그릇처럼 대상을 단순히 가리키는 것을 넘어 특정한 이미지와 정서를 함께 전달한다.</p>
<p>예를 들어 “화이트”라는 언어는 단순히 색을 지시하기도 하지만, 깨끗함, 순수함, 고급스러움 같은 상징적 의미를 함께 전달할 수 있다.</p>
<p>따라서 마케팅에서 언어는 현실을 묘사하는 동시에 현실을 창조한다. 제품의 이름이나 슬로건을 바꾸는 것만으로도 소비자가 제품을 보는 관점이 달라질 수 있다.</p>
<hr>
<h2 id="13-좋아-보이는-제품과-좋은-제품은-다르다">13. 좋아 보이는 제품과 좋은 제품은 다르다</h2>
<p>컨셉을 만들 때 중요한 것은 제품을 “좋아 보이게” 만드는 것이다. 왜냐하면 소비자는 제품을 직접 충분히 사용해보고 구매하는 것이 아니라, 구매 전에는 주로 포장, 외관, 브랜드명, 가격, 원산지, 광고, 품질 단서 등을 보고 판단하기 때문이다.</p>
<blockquote>
<p><strong>좋아 보이는 제품 = 기대치를 높이는 제품</strong>
<strong>좋은 제품 = 실제 사용경험에서 만족을 주는 제품</strong></p>
</blockquote>
<p>컨셉은 제품이 좋아 보이도록 만들어 기대치를 높인다. 그러나 좋은 컨셉만으로는 부족하다. 실제 제품력이 따라오지 않으면 소비자는 실망한다.</p>
<p>자료에서는 이를 “좋아 보이는 것을 실제 좋게 만들라”로 정리한다.</p>
<p>성실은 말을 그대로 이루는 것이다. 컨셉으로 정하기 전에, 컨셉대로 제품의 성능에 만족할 수 있도록 준비해야 한다. 컨셉이 기대를 만들었다면 제품은 그 기대를 충족해야 한다.</p>
<p>결국 성공적인 브랜드는 다음 구조를 가진다.</p>
<blockquote>
<p><strong>좋아 보이는 제품처럼 보이도록 컨셉을 만들어 기대치를 높이고,</strong>
<strong>컨셉대로 제품의 성능을 만들어 기대치를 충족시킨다.</strong></p>
</blockquote>
<p>이것이 브랜드 성공의 핵심이다.</p>
<hr>
<h2 id="14-품질-단서와-품질-신호는-컨셉의-일부다">14. 품질 단서와 품질 신호는 컨셉의 일부다</h2>
<p>소비자는 구매 전에 제품의 진짜 품질을 완벽히 알 수 없다. 그래서 품질을 추론할 수 있는 단서를 찾는다.</p>
<p>자료에서는 이를 <strong>품질 단서</strong>와 <strong>품질 신호</strong>로 정리한다.</p>
<p>품질 단서와 품질 신호에는 언어로 표현 가능한 요소와 언어로 표현하기 어려운 요소가 있다.</p>
<p>언어로 표현 가능한 요소는 브랜드명, 가격, 원산지, 문구, 인증, 설명 등이다. 언어로 표현하기 어려운 요소는 제품 외형, 디자인, 포장, 덴마크 우유의 변화 같은 감각적 요소다.</p>
<p>즉, 소비자는 제품을 구매하기 전에 다양한 품질 단서를 통해 “이 제품은 좋을 것이다”라고 기대한다.</p>
<p>그러나 여기서 중요한 것은 컨셉과 실제 제품력의 일치다. 컨셉만 좋고 제품력이 따라오지 않으면 기대가 배신당한다. 반대로 제품력이 좋아도 컨셉이 없으면 소비자는 그 가치를 인식하지 못한다.</p>
<hr>
<h2 id="15-소비자는-구매-단계에서는-컨셉에-의존하고-사용-단계에서는-경험으로-평가한다">15. 소비자는 구매 단계에서는 컨셉에 의존하고, 사용 단계에서는 경험으로 평가한다</h2>
<p>소비자의 평가 과정은 구매 전과 사용 후로 나누어 볼 수 있다.</p>
<p>구매 단계에서 소비자는 전적으로 컨셉에 의존해서 평가한다. 아직 제품을 실제로 사용해보지 않았기 때문에 브랜드 이미지, 포장, 광고, 가격, 설명, 품질 단서를 보고 판단한다.</p>
<p>사용 단계에서는 물리적 제품을 경험으로 평가한다. 실제로 써보고 제품이 좋은지 나쁜지를 판단한다.</p>
<p>이를 정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>구매 단계</th>
<th>사용 단계</th>
</tr>
</thead>
<tbody><tr>
<td>컨셉</td>
<td>기대 형성</td>
<td>경험과 비교</td>
</tr>
<tr>
<td>물리적 제품</td>
<td>추론 대상</td>
<td>직접 평가 대상</td>
</tr>
<tr>
<td>소비자 판단</td>
<td>좋아 보이는가</td>
<td>실제로 좋은가</td>
</tr>
</tbody></table>
<p>또한 자료에서는 세 가지 경우를 구분한다.</p>
<p>첫째, 구매 단계에서 기대가 높고 사용 단계에서도 경험이 좋으면 반복 구매가 증가한다.</p>
<p>둘째, 구매 단계에서 기대는 높지만 사용 단계에서 경험이 나쁘면 실망하고 반복 구매가 감소한다.</p>
<p>셋째, 구매 단계에서 기대는 낮지만 사용 단계에서 경험이 좋으면 제품이 알려지기까지 시간이 걸리고, 컨셉을 바꾸어야 한다.</p>
<p>따라서 마케팅은 단순히 첫 구매를 만들기 위한 활동이 아니라, 기대와 경험을 일치시키는 활동이어야 한다.</p>
<hr>
<h2 id="16-칸트-구성주의와-브랜드-효과">16. 칸트 구성주의와 브랜드 효과</h2>
<p>칸트의 구성주의 관점에서 우리는 물자체를 그대로 알 수 없다. 우리가 아는 것은 물자체 자체가 아니라, 우리의 인식 형식에 의해 구성된 현상이다.</p>
<p>마케팅에 적용하면, 소비자는 제품 자체를 있는 그대로 인식하는 것이 아니라, 브랜드 효과, 품질 단서, 포장, 원산지, 가격, 브랜드명 등을 통해 구성된 현상을 인식한다.</p>
<p>자료에서는 물자체와 현상을 다음처럼 정리한다.</p>
<blockquote>
<p><strong>물자체 = thing-in-itself = unknown</strong>
<strong>현상 = 우리 앞에 드러난 것 = 개념과 외관에 의해 구성된 것</strong></p>
</blockquote>
<p>브랜드 효과는 일종의 구성 효과다. 소비자는 브랜드를 통해 제품을 해석하고, 그 해석에 따라 품질을 다르게 느낀다.</p>
<p>그래서 blind test와 brand test의 차이가 중요하다.</p>
<blockquote>
<p><strong>Blind Test = 물리적 제품만 체험</strong>
<strong>Brand Test = 브랜드가 포함된 현상 체험</strong></p>
</blockquote>
<p>이 차이는 다음을 보여준다.</p>
<blockquote>
<p><strong>Quality Cue 효과</strong>
<strong>상표명 효과</strong>
<strong>Halo Effect</strong>
<strong>Brand 효과</strong></p>
</blockquote>
<p>감각을 측정하기는 어렵기 때문에, 통계적으로는 브랜드 효과나 품질 단서 효과를 통해 간접적으로 파악할 수 있다.</p>
<hr>
<h2 id="17-감각-기호는-제품을-좋아-보이게-만드는-핵심-도구다">17. 감각 기호는 제품을 좋아 보이게 만드는 핵심 도구다</h2>
<p>마케팅에서 감각 기호는 제품을 좋아 보이게 만드는 도구다. 소비자는 언어 기호와 감각 기호를 함께 받아들인다.</p>
<p>감각 기호에는 색, 형, 음, 물, 촉 등이 포함된다.</p>
<p>자료에서는 감각 기호를 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>색</strong>: 색을 보여주어 생각과 상징을 전달한다.
<strong>형</strong>: 형태를 보여주어 유형성을 전달한다.
<strong>음</strong>: 움직임과 소리를 통해 배경과 분위기를 만든다.
<strong>물</strong>: 물성을 변화시켜 차별화를 만든다.
<strong>촉</strong>: 직접 만지면서 확실히 사용할 수 있게 하고 유형성을 높인다.</p>
</blockquote>
<p>예를 들어 색은 생명, 청결, 고급스러움, 안정감 등을 전달할 수 있다. 형태는 제품의 기능성과 사용 방식을 암시한다. 소리는 분위기와 감정을 만든다. 촉감은 제품의 실재감을 높인다.</p>
<p>중요한 것은 감각의 모든 요소가 컨셉 전체와 연결되어야 한다는 점이다. 감각 요소 하나가 가장 큰 영향을 줄 수도 있지만, 결국 PASS 전체를 고려해 차별화를 줄 수 있어야 한다.</p>
<hr>
<h2 id="18-생명동률과-성향미-감각-대상을-세분화하라">18. 생명동률과 성향미: 감각 대상을 세분화하라</h2>
<p>자료에서는 감각 대상을 세분화하면서 생명동률과 성향미를 언급한다.</p>
<p>감각 대상은 색, 형, 음, 물, 촉으로 나눌 수 있고, 이를 다시 생명동률과 성향미로 세분화할 수 있다.</p>
<p>예를 들어 색과 관련해서는 공감각적이고 생리적인 효과를 고려할 수 있다. 성향미와 관련해서는 성향적, 시간적, 심리적 특징을 고려할 수 있다.</p>
<p>이를 컨셉 개발에 적용하면 다음과 같다.</p>
<p>첫째, 제품 컨셉을 위해 색, 형, 음, 물, 촉을 나누어 생각한다.</p>
<p>둘째, 상징으로 브랜드를 개발하기 위해 생명동률과 성향미를 나누어 생각한다.</p>
<p>셋째, 생명동률과 성향미에 PASS를 결합하면 다양한 아이디어가 나온다.</p>
<p>자료에서는 이를 다음처럼 정리한다.</p>
<blockquote>
<p><strong>생명동률 + 성향미 × PASS = 여러 가지 컨셉 차별화 가능성</strong></p>
</blockquote>
<p>이처럼 감각을 세분화하면 막연한 디자인이 아니라, 컨셉에 맞는 감각 설계가 가능해진다.</p>
<hr>
<h2 id="19-pass-차별화-제품-출시-전부터-마케팅-전략까지-연결된다">19. PASS 차별화: 제품 출시 전부터 마케팅 전략까지 연결된다</h2>
<p>PASS는 제품의 시장 출시 전에는 브랜드 컨셉에 우선하고, 4P는 제품의 시장 출시 후 마케팅 전략에 개입된다.</p>
<p>자료에서는 PASS를 단순한 품질 요소가 아니라 차별화 전략으로 본다.</p>
<p>PASS 차별화는 제품 자체만 바꾸는 것이 아니라, 소비자들이 제품을 보게 되는 차별화된 포인트를 만들어내는 것이다.</p>
<p>PASS의 세부 요소는 다음처럼 정리할 수 있다.</p>
<blockquote>
<p><strong>Performance</strong>: 성능
<strong>Appearance</strong>: 외관
<strong>Supplement</strong>: 보완 요소, 부가서비스
<strong>Short Process</strong>: 구매·사용 과정의 간결함</p>
</blockquote>
<p>PASS는 소비자에게 제품을 어떻게 인식시킬지 결정하는 데 사용된다. 제품 범주, 브랜드명, 표적고객, 속성·편익, 유형성, 식역적 품질, 성향미, 스토리와 연결된다.</p>
<p>PASS 차별화는 단순히 “제품을 다르게 만들자”가 아니라, 소비자가 제품의 차이를 인식할 수 있도록 만드는 전략이다.</p>
<hr>
<h2 id="20-상징은-브랜드에-정신적-의미를-부여한다">20. 상징은 브랜드에 정신적 의미를 부여한다</h2>
<p>상징은 마케팅에서 매우 중요하다. 물리적 제품만으로는 소비자의 마음에 깊이 남기 어렵다. 제품은 상징을 통해 정신적 의미를 얻는다.</p>
<p>자료에서는 상징을 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>상징 = 상징물 + 정신적 의미</strong></p>
</blockquote>
<p>상징은 우리가 위히 알거나 볼 수 있는 것으로, 알지 못하거나 볼 수 없는 것을 암시하는 것이다. 예를 들어 말보로맨은 남성성을 암시하는 상징물이다. 소비자는 상징물을 보고, 그 상징을 해석하여 정신적 의미를 느낀다.</p>
<blockquote>
<p><strong>물리체는 범주를 통해 표상된다.</strong>
<strong>상징물은 상징을 통해 정신적 의미가 된다.</strong></p>
</blockquote>
<p>감각적 상징으로 물리적 제품을 상징화하는 것이 브랜딩이다. 브랜드는 단순한 상표가 아니라, 물리적 제품을 대신하는 상징물이다.</p>
<p>브랜드는 상표이고, 물리적 제품을 대신하며, 상징물로 기능한다. 여기에 추가적으로 성격이나 정신적 의미를 가지면 상징이 된다.</p>
<p>예를 들어 제품이 상징물로 제시되고, 거기에 남성성, 자유, 세련됨, 전문성, 청춘 같은 정신적 의미가 부여되면 소비자는 제품을 단순 물건이 아니라 의미 있는 대상으로 인식한다.</p>
<hr>
<h2 id="21-상징은-중요하지만-제품과-균형을-맞춰야-한다">21. 상징은 중요하지만, 제품과 균형을 맞춰야 한다</h2>
<p>상징이 중요한 것은 맞지만, 상징만 중요한 것은 아니다. 상징과 제품의 균형이 필요하다.</p>
<p>자료에서는 “상징이 만들어지기 전까지는 대상이 우리에게 가까워지고, 만들어진 뒤에는 상징으로 둘러싸여 살게 된다”고 정리한다. 상징이 만들어지면 물리적 제품은 소비자의 인식 속에서 상징과 함께 느껴진다.</p>
<p>하지만 상징이 너무 앞서가고 제품이 따라오지 않으면 소비자는 실망한다. 반대로 제품은 좋지만 상징이 없으면 소비자의 마음에 남기 어렵다.</p>
<p>따라서 마케팅에서는 다음이 필요하다.</p>
<blockquote>
<p><strong>상징 + 제품 + 브랜드의 시장흐름 + 주력된 생산방식 + 상징의 구성요소 + 전체화</strong></p>
</blockquote>
<p>즉, 상징과 제품, 브랜드 전략, 생산방식, 소비자 인식이 모두 연결되어야 한다. 그렇지 않으면 마케팅은 공허하거나 맹목적이 된다.</p>
<hr>
<h2 id="22-스토리는-브랜드-컨셉을-전달하는-강력한-방법이다">22. 스토리는 브랜드 컨셉을 전달하는 강력한 방법이다</h2>
<p>브랜드 컨셉을 효과적으로 전달하기 위해서는 스토리가 필요하다.</p>
<p>자료에서는 스토리를 개발하라는 내용을 다음처럼 정리한다.</p>
<blockquote>
<p>성공한 브랜드가 되기 위해서는 사람들이 계속해서 서로 이야기를 나눌 수 있는 브랜드 스토리를 제공해야 한다.</p>
</blockquote>
<p>스토리는 소비자가 브랜드를 단순 정보로 받아들이는 것이 아니라, 사건과 감정의 흐름으로 이해하게 만든다.</p>
<p>스토리의 시작은 어떤 사건에 의해 삶의 균형이 무너지는 것이다. 그 균형을 회복하려는 여러 차례의 시도가 이야기를 만든다. 따라서 브랜드 스토리도 소비자의 문제, 갈등, 해결, 변화의 구조를 가져야 한다.</p>
<p>좋은 브랜드 스토리는 다음을 가능하게 한다.</p>
<p>첫째, 고객이 공감할 수 있는 주인공을 만든다.</p>
<p>둘째, 고객이 알고 있는 개념과 경험을 활용한다.</p>
<p>셋째, 고객의 심리적 저항을 줄인다.</p>
<p>넷째, 소비자가 브랜드를 더 잘 전달받게 한다.</p>
<p>스토리는 정보 전달보다 강하다. 왜냐하면 이야기는 사실과 감정의 조합으로 기억되기 때문이다.</p>
<hr>
<h2 id="23-감각의-비빔밥을-만들어라">23. 감각의 비빔밥을 만들어라</h2>
<p>여러 감각이 동시에 결합하면 서로 간에 화학반응을 일으켜 더 많은 인지반응과 정서반응을 유발할 수 있다. 이를 자료에서는 “감각의 비빔밥”처럼 설명한다.</p>
<p>하지만 감각 요소를 무작정 결합하면 안 된다. 항상 하나의 컨셉이 다른 감각의 재료를 꿰어 일관성을 유지해야 한다. 그렇지 않으면 감각은 풍부하지만 메시지가 흐려진다.</p>
<p>여러 감각 재료를 사용하면 다중 부호 효과로 전달 확률을 높일 수 있고, 정서적 반응도 높일 수 있다. 그러나 제품은 서비스처럼 구매와 사용이 같은 시간과 공간에서 일어나는 것이 아니라, 분리되어 있다. 따라서 구매 시점에서 제품에 없는 다른 감각 경험을 어떻게 결합할 것인지 고민해야 한다.</p>
<p>예를 들어 기아 향, 토르크 향, 구분통에서 사용 시점에 가능한 경험 제공 같은 방식이 가능하다. 또한 감각의 변형도 활용할 수 있다.</p>
<p>자료에서는 예시로 몽타주를 든다.</p>
<blockquote>
<p>입자 → 소리
소리 → 해동 이미지</p>
</blockquote>
<p>이처럼 감각을 다른 감각으로 번역하거나 변형하면 새로운 브랜드 경험을 만들 수 있다.</p>
<hr>
<h2 id="24-컨셉은-시간-흐름-속에서-발전한다">24. 컨셉은 시간 흐름 속에서 발전한다</h2>
<p>컨셉은 한 번에 완성되는 것이 아니라, 시간 흐름 속에서 발전한다.</p>
<p>자료에서는 시간 흐름을 크게 세 단계로 정리한다.</p>
<p>첫째, <strong>제품 컨셉</strong> 단계다. 이 단계에서는 물리적 제품 형상화, 이상 언어, 제품 개발 방향, PASS가 중요하다. 출시 전 단계에 해당한다.</p>
<p>둘째, <strong>포지셔닝 서술</strong> 단계다. 이 단계에서는 개념적 묘사, 구체화, 제품 컨셉에서 표현 컨셉으로의 강력한 연결, 4P와 마케팅 전략 통합이 중요하다. 출시 임박 단계에 해당한다.</p>
<p>셋째, <strong>표현 컨셉</strong> 단계다. 이 단계에서는 구체적이고 함축적이며 비유적인 언어가 사용된다. 상징화, 감성적 표현, 소비자가 구매하도록 그 이유를 제시하고 설득하는 과정이 중요하다.</p>
<p>정리하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>단계</th>
<th>핵심 내용</th>
<th>목적</th>
</tr>
</thead>
<tbody><tr>
<td>제품 컨셉</td>
<td>제품 형상화, 이상 언어, 개발 방향, PASS</td>
<td>출시 전 방향 설정</td>
</tr>
<tr>
<td>포지셔닝 서술</td>
<td>개념적 묘사, 구체화, 4P 연결</td>
<td>출시 임박 전략화</td>
</tr>
<tr>
<td>표현 컨셉</td>
<td>함축적 언어, 상징화, 소비자 언어</td>
<td>구매 설득</td>
</tr>
</tbody></table>
<p>출시가 임박할수록 세 단계는 서로 상생해야 컨셉 효과가 커진다.</p>
<hr>
<h2 id="25-친숙한-개념으로-컨셉을-kiss하라">25. 친숙한 개념으로 컨셉을 KISS하라</h2>
<p>좋은 컨셉은 소비자가 빨리 이해하고 기억할 수 있어야 한다. 이를 위해서는 이미 익숙히 알고 있는 개념과 새로운 개념을 연결해야 한다.</p>
<p>자료에서는 이를 “친숙한 개념으로 컨셉을 KISS하라”라고 정리한다.</p>
<p>정의는 다음과 같은 구조를 가진다.</p>
<blockquote>
<p><strong>정의 = 유개념 + 종차</strong>
<strong>정의 = 상위 개념 + 하위 개념</strong>
<strong>정의 = 제품 범주 + 속성·편익</strong></p>
</blockquote>
<p>인간은 상위 개념을 먼저 배우고 하위 개념을 배울수록 개념이 더 친숙해진다. 따라서 새로운 제품이나 브랜드를 설명할 때는 소비자가 이미 알고 있는 상위 개념을 활용해야 한다.</p>
<p>예를 들어 브랜드를 소개할 때 “완전히 새로운 것”이라고만 하면 이해가 어렵다. 대신 기존 범주와 비교하면서 무엇이 다른지 보여주면 이해가 쉬워진다.</p>
<p>자료에서는 차별화와 속성·편익을 기준으로 다음과 같은 비교를 제시한다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>종차</th>
<th>유개념</th>
</tr>
</thead>
<tbody><tr>
<td>차별화</td>
<td>속성·편익</td>
<td>제품 범주</td>
</tr>
<tr>
<td>브랜딩</td>
<td>새로운 고객·고객</td>
<td>제품 범주</td>
</tr>
<tr>
<td>정의 방법</td>
<td>A 제품 범주와 같은 점 / 다른 점</td>
<td>B 제품 범주와 같은 점 / 다른 점</td>
</tr>
</tbody></table>
<p>핵심은 소비자가 브랜드를 안다는 것이 제품이나 브랜드가 존재하는 이유, 즉 목적과 편익을 아는 것이라는 점이다.</p>
<hr>
<h2 id="26-소비자-눈높이의-언어로-말하라">26. 소비자 눈높이의 언어로 말하라</h2>
<p>마케팅 언어는 기업 내부 언어가 아니라 소비자 언어여야 한다. 소비자와 소통할 때는 소비자의 일상 언어로 바꾸어 말해야 한다.</p>
<p>자료에서는 언어를 <strong>이상언어</strong>와 <strong>일상언어</strong>로 나눈다.</p>
<p>이상언어는 사물을 있는 그대로 그린 것처럼 보이며, 과학적이고 공학적이며 객관적이고 정확한 언어다. 기술자나 전문가에게는 적합하지만, 소비자에게는 어렵게 느껴질 수 있다.</p>
<p>일상언어는 일상에서 마음속 이미지를 상징화하는 언어다. 소비자 언어에 가깝고, 이미지와 감정, 경험을 담는다.</p>
<p>마케팅에서는 이상언어만 사용하면 소비자가 이해하기 어렵다. 그렇다고 일상언어만 사용하면 정확성이 떨어질 수 있다. 따라서 이상언어와 일상언어를 구분하고, 상황에 맞게 적절한 언어를 사용해야 한다.</p>
<p>자료에서는 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>표상은 언어의 표현에 의해 개념이 되는 언어화된 개념이다.</strong>
<strong>개념은 개념 체계 안에서 상대적 의미가 정해진다.</strong>
<strong>따라서 일상언어는 상대적 의미를 가진다.</strong></p>
</blockquote>
<p>즉, 소비자에게 말할 때는 객관적 설명만이 아니라, 소비자가 일상에서 어떤 의미로 받아들일지를 고려해야 한다.</p>
<hr>
<h2 id="27-숨어-있는-사회적-욕구를-헤아려라">27. 숨어 있는 사회적 욕구를 헤아려라</h2>
<p>소비자의 욕구는 기능적 욕구만으로 설명되지 않는다. 자료에서는 욕구를 기능적 욕구, 감성적 욕구, 사회적 욕구로 나눈다.</p>
<blockquote>
<p><strong>기능적 욕구 = 기능재</strong>
<strong>감성적 욕구 = 경험재</strong>
<strong>사회적 욕구 = 사회재, 상징재</strong></p>
</blockquote>
<p>기능적 욕구와 감성적 욕구를 성공적으로 제시해도, 사회적 동기를 고려하지 못하면 소비자의 외면을 받을 수 있다.</p>
<p>사람은 남과 동감하려는 본능을 가지고 있다. 타인의 칭찬을 얻고 싶어 하고, 비난을 피하고 싶어 하며, 때로는 과시 소비를 한다. 소비자는 자신이 타인에게 어떻게 보이는지를 의식한다.</p>
<p>따라서 제품은 단순히 문제를 해결하는 도구가 아니라, 소비자가 자신을 드러내고 싶은 방식과 연결된다. 어떤 제품을 사용하는 것은 타인에게 비추는 자신의 모습을 선택하는 일이기도 하다.</p>
<p>자료에서는 감춰진 욕구를 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>상품 동감</strong>
<strong>비난 회피</strong>
<strong>칭찬 욕구</strong></p>
</blockquote>
<p>마케팅은 소비자의 기능적·감성적 동기뿐 아니라, 사회적 동기까지 고려해야 한다.</p>
<hr>
<h2 id="28-모든-법칙을-무시하고-자신의-법칙을-만들어라">28. 모든 법칙을 무시하고 자신의 법칙을 만들어라</h2>
<p>자료에서는 기존 법칙을 절대적인 것으로 따르기보다, 상황에 맞는 자신의 법칙을 만들어야 한다고 정리한다.</p>
<p>법칙은 고정된 것이 아니다. 법칙들과 이를 부정하는 법칙들이 모여 더 완전한 법칙을 만든다. 따라서 기존 법칙을 보존하는 모방자의 법칙이 아니라, 자기만의 법칙으로 만들어야 한다.</p>
<p>마케팅에 적용하면 중요한 것은 고정된 법칙보다 소비자에게 사야 할 이유를 잘 제시하고, 그들을 만족시킬 수 있는 수준을 고르는 것이다.</p>
<p>자료에서는 부처님의 연기론도 함께 연결한다.</p>
<blockquote>
<p><strong>모든 현상은 여러 조건이 서로 의존하면서 만들어지고, 조건이 없어지면 현상도 변한다.</strong></p>
</blockquote>
<p>성공은 여러 조건들이 결합되어 생기는 것이다. 어떤 조건들이 사라지면 성공도 실패로 바뀔 수 있다. 기록만 보면 승자들이 필연적으로 승리한 것처럼 보이지만, 실제로는 여러 조건이 결합된 결과다.</p>
<p>마케팅에서도 하나의 성공 법칙이 언제나 통하는 것은 아니다. 조건과 맥락을 보고 자기만의 전략을 만들어야 한다.</p>
<hr>
<h2 id="29-공감은-소비자-관계의-핵심이다">29. 공감은 소비자 관계의 핵심이다</h2>
<p>자료에서는 공감의 층위를 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>Sympathy</strong>: 동정
<strong>Empathy</strong>: 감정이입
<strong>마음이론</strong>: 역지사지
<strong>Fellow-feeling</strong>: 동료애, 공명</p>
</blockquote>
<p>공감을 잘하기 위해서는 관찰, 유사성, 인간성이 필요하다. 소비자의 감정을 이해하려면 단순히 데이터를 보는 것만으로는 부족하다. 소비자가 어떤 상황에 있고, 어떤 욕구와 두려움을 가지고 있으며, 어떤 언어로 세상을 이해하는지 봐야 한다.</p>
<p>공감은 브랜드 스토리와도 연결된다. 브랜드가 소비자의 문제와 감정을 잘 포착하면 소비자는 그 브랜드를 “나를 이해하는 브랜드”로 느낀다.</p>
<hr>
<h2 id="30-기업은-어디에서-시작되었는가-길드-주식회사-산업혁명">30. 기업은 어디에서 시작되었는가: 길드, 주식회사, 산업혁명</h2>
<p>마케팅을 이해하려면 기업의 역사도 이해해야 한다.</p>
<p>자료에서는 기업의 시작을 중세 길드에서 찾는다. 길드는 같은 업종의 장인들이 모여 권익을 보호하던 조직이다.</p>
<p>길드의 기업가 정신에는 두 가지 면이 있었다.</p>
<p>첫째, 공동체적 성격이다. 공동의 이익을 추구하고, 내부 결재와 독점적 지위를 유지했다.</p>
<p>둘째, 차이성이다. 길드는 기술을 축적하고 경쟁을 막는 폐쇄적 구조를 가졌다.</p>
<p>이후 대항해 시대에 주식회사와 증권거래소가 탄생했다. 네덜란드의 동인도회사와 암스테르담 증권거래소는 주식회사의 씨앗이 되었다.</p>
<p>18세기 산업혁명 이후 기업은 수공업에서 공장제 대량생산으로 발전했다. 기업은 법의 보호와 권리를 받으며 법인으로 인정되었다.</p>
<p>애덤 스미스의 『국부론』에서는 중상주의를 비판하고, 경제적 자유를 강조했다. 중상주의의 비판점은 독점 공급과 이를 비호하는 중상주의가 모든 사람에게 경제적 자유를 보여주지 못한다는 것이다.</p>
<p>경제 구조는 다음과 같이 볼 수 있다.</p>
<blockquote>
<p><strong>C + I + G</strong>
<strong>소비 + 투자 + 정부 유지</strong></p>
</blockquote>
<p>지속적 성장을 위해서는 생산성과 고용률을 높여야 한다. 생산성은 총생산량을 전체 인구나 고용률과 연결해 볼 수 있다.</p>
<hr>
<h2 id="31-기업은-기계보다-유기체에-가깝다">31. 기업은 기계보다 유기체에 가깝다</h2>
<p>자료에서는 기업이 기계보다 유기체가 되어야 한다고 정리한다.</p>
<p>조직한다는 것은 유기체처럼 만든다는 의미다. 기업은 분업되고 전문화되지만, 각 기능이 따로 떨어져 있으면 안 된다. 전문화된 기능들이 유기적으로 상호작용해야 한다.</p>
<p>기업에는 내적 적합성과 외적 적합성이 동시에 필요하다.</p>
<blockquote>
<p><strong>내적 적합성 = 조직 내부 기능의 통합</strong>
<strong>외적 적합성 = 환경 적응</strong></p>
</blockquote>
<p>마케팅도 이 관점에서 봐야 한다. 마케팅은 특정 부서만의 일이 아니라, 기업 전체가 고객가치와 고객관계를 중심으로 유기적으로 움직이는 과정이다.</p>
<hr>
<h2 id="32-마케팅-전략은-stp와-마케팅-믹스의-통합이다">32. 마케팅 전략은 STP와 마케팅 믹스의 통합이다</h2>
<p>마케팅 전략은 STP와 마케팅 믹스로 구성된다.</p>
<blockquote>
<p><strong>STP = Segmentation + Targeting + Positioning</strong>
<strong>Marketing Mix = Product + Price + Promotion + Place</strong></p>
</blockquote>
<p>자료에서는 STP를 다음과 같이 정리한다.</p>
<p>기업은 고객, 기업 제공물, 경쟁 제공물을 고려해야 한다. 여기서 카테고리, 타깃, 필요성, 차별성, 유형성이 나온다. 그리고 이를 통해 포지셔닝을 결정한다.</p>
<p>포지셔닝은 “어떤 시장에서, 어떤 고객에게, 어떤 필요와 차별성을 제시할 것인가”를 결정하는 과정이다.</p>
<p>그다음 마케팅 전략은 제품, 가격, 360도 커뮤니케이션, 유통으로 이어진다. 이 과정에서 소비자가 느끼는 가격 대비 가치가 형성되고, 가격 수준과 원가, 수익성이 연결된다.</p>
<p>정리하면 다음과 같다.</p>
<blockquote>
<p><strong>Company → Customer / Company Offering</strong>
<strong>Category → Target / A-B 차별화</strong>
<strong>Positioning → Marketing Strategy</strong>
<strong>Marketing Strategy → Perceived Value → Price Level / Cost / Profitability</strong></p>
</blockquote>
<p>마케팅은 포지셔닝과 4P를 따로 보는 것이 아니라, 하나의 시스템으로 작동시켜야 한다.</p>
<hr>
<h2 id="33-컨셉-마케팅에서-stp는-컨셉-서술문으로-대체된다">33. 컨셉 마케팅에서 STP는 컨셉 서술문으로 대체된다</h2>
<p>자료에서는 컨셉 마케팅에서 STP를 컨셉 서술문으로 대체한다고 정리한다.</p>
<p>컨셉 서술문은 제품 범주, 표적고객, 속성·편익을 포함한다.</p>
<blockquote>
<p><strong>컨셉 서술문 = 제품 범주 + 표적고객 + 속성·편익</strong></p>
</blockquote>
<p>예를 들어 “끌리는 컨셉의 법칙”은 마케팅 원리 이상의 실무자를 위한 마케팅 전략서로서, 컨셉의 성공과 실패 사례를 제시하고, 속성 마케팅 응용을 향상시키는 식으로 표현될 수 있다.</p>
<p>여기서 속성은 실제에 대한 설명 요소이고, 표현은 속성을 통해 궁극적으로 받아들여지는 영향이다.</p>
<p>즉, 컨셉 서술문은 단순 설명이 아니라, 소비자가 제품을 어떤 범주에 넣고, 어떤 편익을 기대해야 하는지 알려주는 역할을 한다.</p>
<hr>
<h2 id="34-전통적-마케팅에는-컨셉이-빠져-있었다">34. 전통적 마케팅에는 컨셉이 빠져 있었다</h2>
<p>자료에서는 전통적 마케팅이 컨셉을 충분히 다루지 못했다고 본다.</p>
<p>전통적 마케팅에서는 다음과 같은 구조가 나타난다.</p>
<blockquote>
<p>아이디어 → 제품 컨셉 → 물리적 제품 → 완전한 인식</p>
</blockquote>
<p>그러나 여기에서 소비자 언어와 기술자 언어의 차이, 표현 컨셉의 역할, 감각과 개념의 결합이 충분히 다루어지지 않을 수 있다.</p>
<p>컨셉 마케팅은 이 빈 부분을 보완한다. 마케팅은 고객에게 컨셉을 제시하고, 사용자의 감각의 틀을 주입시키고, 특정한 경험에서 제품이 떠오르게 하는 것이다.</p>
<p>자료에서는 이를 다음처럼 정리한다.</p>
<blockquote>
<p>결국 마케팅은 고객에게 컨셉을 제시하여 사용자의 감각의 틀을 주입시키고, 특정 경험에서 제품이 떠오르게 하는 것이다.</p>
</blockquote>
<p>이 문장은 전체 내용을 관통하는 핵심이다.</p>
<hr>
<h2 id="35-마케팅은-고객가치와-고객관계를-관리하는-조직적-기능이다">35. 마케팅은 고객가치와 고객관계를 관리하는 조직적 기능이다</h2>
<p>자료에서는 마케팅을 다음과 같이 정의한다.</p>
<blockquote>
<p><strong>마케팅은 고객에게 가치를 창출, 의사소통, 전달하여 고객관계를 관리하는 조직적 기능과 일련의 과정이다.</strong></p>
</blockquote>
<p>여기서 중요한 것은 두 가지다.</p>
<p>첫째, <strong>고객가치</strong>다. 마케팅은 제품을 파는 것이 아니라 고객에게 가치를 만드는 일이다.</p>
<p>둘째, <strong>고객관계</strong>다. 마케팅은 한 번의 거래로 끝나는 것이 아니라, 고객과의 관계를 만들고 유지하는 일이다.</p>
<p>마케팅은 고객과의 공감, 상호작용, 애덤 스미스적 도덕감정론의 관점과도 연결된다. 고객을 단순히 구매자로 보는 것이 아니라, 감정과 욕구를 가진 사람으로 이해해야 한다.</p>
<p>마케팅 성과는 매출과 이익으로 나타난다. 세부적으로는 재구매, 구매, 선호, 취급률, 인지율 등이 포함된다.</p>
<hr>
<h2 id="36-비즈니스-성공-요인은-운영-효율-제품-차별화-고객-친밀성이다">36. 비즈니스 성공 요인은 운영 효율, 제품 차별화, 고객 친밀성이다</h2>
<p>자료에서는 비즈니스 성공 요인을 세 가지로 정리한다.</p>
<blockquote>
<p><strong>Operational Excellence = 운영 효율</strong>
<strong>Product Differentiation = 제품 차별화</strong>
<strong>Customer Intimacy = 고객 친밀성</strong></p>
</blockquote>
<p>운영 효율은 주로 유통이나 운영 시스템과 관련된다. 제품 차별화는 제품 자체와 관련된다. 고객 친밀성은 서비스와 관계에 가깝다.</p>
<p>중요한 것은 세 가지 중 하나가 뛰어나면 나머지도 평균 이상은 되어야 한다는 점이다. 특정 하나만 극단적으로 강하고 다른 요소가 너무 약하면 전체 가치사슬이 무너진다.</p>
<hr>
<h2 id="37-가치사슬은-출발점부터-다르게-볼-수-있다">37. 가치사슬은 출발점부터 다르게 볼 수 있다</h2>
<p>가치사슬은 반드시 원자재나 생산 단계에서 시작할 필요가 없다. 성공 요인에 따라 가치사슬의 출발점은 달라질 수 있다.</p>
<p>제조는 생산 체인을 보고, 서비스는 소비 체인을 보아야 한다. 서비스는 제공자와 생산자, 소비자가 동시에 이루어지기 때문에 접점 관리가 중요하다.</p>
<p>가치사슬에는 핵심기능과 보조기능이 있다. 보조기능에는 연구개발, 제품 설계, 구매 물류, 제조, 출하 물류, 판매, A/S 등이 포함된다.</p>
<p>마케팅은 이 전체 가치사슬 안에서 고객가치가 어디에서 만들어지고, 어디에서 전달되고, 어디에서 훼손되는지를 봐야 한다.</p>
<hr>
<h2 id="38-마케팅-믹스는-시너지로-작동해야-한다">38. 마케팅 믹스는 시너지로 작동해야 한다</h2>
<p>STP와 마케팅 믹스는 분리된 것이 아니라 연결되어야 한다. 자료에서는 마케팅 믹스를 통합하여 시너지를 창출해야 한다고 정리한다.</p>
<blockquote>
<p><strong>Product, Price, Promotion, Place는 따로 작동하는 것이 아니라 하나의 시스템처럼 작동해야 한다.</strong></p>
</blockquote>
<p>이를 system approach라고 볼 수 있다.</p>
<blockquote>
<p><strong>System Approach = Total and Systematic Response</strong></p>
</blockquote>
<p>즉, 네 가지 요소를 모두 준비해서 한 번에 터뜨려야 한다. 마케팅 믹스는 마케팅 수단을 넣은 후에 유기적으로 작동해야 한다.</p>
<p>또한 레버리지 방식도 중요하다. 큰 문제를 작은 문제로 나눈 뒤, 작은 문제들의 해결책을 구해 전체 문제를 해결하는 방식이다. 데카르트와 맥킨지식 문제 해결 방식처럼 문제를 분해하고 합성해야 한다.</p>
<hr>
<h2 id="39-포지셔닝은-소비자-인식-단계에-맞게-바뀌어야-한다">39. 포지셔닝은 소비자 인식 단계에 맞게 바뀌어야 한다</h2>
<p>자료에서는 카메라 렌즈 필름 재포지셔닝 사례로 게토레이를 언급한다.</p>
<p>재포지셔닝에서는 정보를 통한 원인 파악이 필요하다. FGI, A&amp;U 조사 등이 사용된다. 소비자가 왜 제품을 사지 않는지, 어떤 이미지 문제가 있는지, 광고 모델이나 디자인 세련도 문제가 있는지 파악해야 한다.</p>
<p>포지셔닝이 성공하려면 소비자 인식 단계별로 접근해야 한다.</p>
<p>소비자 인식 단계는 다음과 같다.</p>
<blockquote>
<p><strong>인지 → 태도 → 구매</strong></p>
</blockquote>
<p>인지 단계에서는 제품이 무엇인지 알게 해야 한다. 태도 단계에서는 선호와 정보에 대한 반응을 바꾸어야 한다. 구매 단계에서는 실제 구매와 극복 촉진이 중요하다.</p>
<p>각 단계별로 매체별 역할을 배분해야 하며, 이론은 독립적이지 않고 일관되게 이어져야 한다.</p>
<hr>
<h2 id="40-마케팅-리서치는-소비자와-마케터를-정보로-연결한다">40. 마케팅 리서치는 소비자와 마케터를 정보로 연결한다</h2>
<p>마케팅 리서치는 소비자, 고객, 일반 대중과 마케터를 정보로 연결하는 기능이다.</p>
<p>자료에서는 마케팅 리서치의 정의를 다음과 같이 정리한다.</p>
<blockquote>
<p><strong>마케팅 리서치 = 소비자, 고객, 일반 대중과 마케터를 정보로 연결하는 기능</strong></p>
</blockquote>
<p>마케팅 리서치는 다음 일을 한다.</p>
<p>첫째, 마케팅 기회와 문제를 발견하고 정의한다.</p>
<p>둘째, 마케팅 행동을 만들고 수정하고 평가한다.</p>
<p>셋째, 마케팅 성과를 점검한다.</p>
<p>넷째, 마케팅 과정을 더 잘 이해하게 한다.</p>
<p>마케팅 리서치가 하는 구체적인 일은 다음과 같다.</p>
<ol>
<li>필요한 정보를 무엇인지 정한다.</li>
<li>정보 수집 방법을 설계한다.</li>
<li>자료 수집 과정을 고려하고 실행한다.</li>
<li>결과를 분석한다.</li>
<li>결과를 의사결정에 활용한다.</li>
</ol>
<p>마케팅 리서치는 문제 인식에서 시작한다.</p>
<blockquote>
<p><strong>문제 인식 → 방향 설정 → 행동안 확정 → 평가 및 개선</strong></p>
</blockquote>
<p>각 단계에는 탐색 리서치, 전략 리서치, 평가 리서치가 연결된다.</p>
<p>탐색 리서치는 고객의 니즈를 해석하고 방향을 잡기 위한 리서치다. 전략 리서치는 포지셔닝 고려와 광고 변화를 고민하기 위한 리서치다. 평가 리서치는 결과를 관찰하고 개선하기 위한 리서치다.</p>
<p>리서치는 비일상적 마케팅 문제에서 일상적 마케팅 문제로 갈수록 더 관리 가능한 방식으로 변한다.</p>
<hr>
<h2 id="41-최종-정리-마케팅은-컨셉을-통해-소비자의-세계를-바꾸는-일이다">41. 최종 정리: 마케팅은 컨셉을 통해 소비자의 세계를 바꾸는 일이다</h2>
<p>한 학기 동안 정리한 내용을 하나로 묶으면, 마케팅은 다음과 같이 정의할 수 있다.</p>
<blockquote>
<p><strong>마케팅은 제품을 직접 파는 기술이 아니라, 소비자가 제품을 의미 있게 인식하도록 컨셉을 설계하고, 그 컨셉을 언어·감각·상징·스토리·가격·유통·경험으로 일관되게 구현하는 과정이다.</strong></p>
</blockquote>
<p>소비자는 물리적 제품만 구매하지 않는다. 소비자는 제품이 주는 가치, 의미, 감각, 상징, 사회적 인정, 자기표현, 사용경험을 함께 구매한다.</p>
<p>그래서 좋은 마케팅은 다음 조건을 갖는다.</p>
<p>첫째, 소비자에게 명확한 <strong>사야 할 이유</strong>를 제시해야 한다.</p>
<p>둘째, 그 이유는 <strong>필요성, 차별성, 유형성</strong>으로 구성되어야 한다.</p>
<p>셋째, 컨셉은 <strong>언어와 감각</strong>을 통해 소비자 인식으로 전환되어야 한다.</p>
<p>넷째, 브랜드는 제품을 넘어 <strong>상징과 정신적 의미</strong>를 가져야 한다.</p>
<p>다섯째, 좋은 컨셉은 제품을 좋아 보이게 만들지만, 실제 제품력도 그 기대를 충족해야 한다.</p>
<p>여섯째, STP와 4P, 가치사슬, 고객관계, 리서치가 모두 하나의 시스템으로 연결되어야 한다.</p>
<p>결국 마케팅의 핵심은 이것이다.</p>
<blockquote>
<p><strong>좋은 제품을 만드는 것만으로는 부족하다.</strong>
<strong>좋아 보이게 만들어 기대를 만들고, 실제로 좋게 만들어 그 기대를 충족시켜야 한다.</strong>
<strong>그리고 그 모든 과정을 하나의 컨셉으로 일관되게 묶어야 한다.</strong></p>
</blockquote>
<p>이 관점에서 마케팅은 단순한 판매 기술이 아니라, 소비자의 인식과 경험을 설계하는 종합적인 사고 체계라고 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] THE LOTTERY TICKET HYPOTHESIS:
FINDING SPARSE, TRAINABLE NEURAL NETWORKS]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-THE-LOTTERY-TICKET-HYPOTHESISFINDING-SPARSE-TRAINABLE-NEURAL-NETWORKS</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-THE-LOTTERY-TICKET-HYPOTHESISFINDING-SPARSE-TRAINABLE-NEURAL-NETWORKS</guid>
            <pubDate>Tue, 26 May 2026 11:42:32 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li><strong>기본 정보:</strong> ICLR 2019에서 발표된 Jonathan Frankle과 Michael Carbin(MIT CSAIL)의 논문 &quot;The Lottery Ticket Hypothesis: Finding Sparse, Trainable Neural Networks&quot;입니다.</li>
<li><strong>목적 및 제안 방법:</strong> 무작위로 초기화된 빽빽한(dense) 신경망 내부에 원본 네트워크와 동일하거나 더 높은 성능을 내는 희소한(sparse) 부분 신경망인 &#39;당첨 티켓(Winning Ticket)&#39;이 존재함을 밝히고, 반복적 가지치기(Iterative Pruning)와 초기화 가중치 복원(Reset) 기법을 통해 이를 추출하는 방법을 제안합니다.</li>
<li><strong>의의:</strong> 기존 방법론이 학습 완료 후 추론 단계의 모델 압축에만 집중했던 한계를 극복하고, 학습 초기부터 효율적으로 훈련될 수 있는 구조와 초기화의 결합을 증명함으로써 신경망 최적화 및 일반화(Generalization) 이론에 대한 새로운 통찰을 제공합니다.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<ul>
<li><strong>연구 배경 및 분야의 흐름:</strong> 딥러닝 분야에서는 모델 압축 및 가지치기(Pruning) 기법을 통해 학습된 네트워크의 파라미터를 90% 이상 줄이면서도 정확도를 유지해 왔습니다. 이를 통해 모델의 저장 공간을 줄이고 추론(Inference) 단계의 연산 효율을 크게 향상시켰습니다.</li>
<li><strong>기존 방법들의 핵심 접근 방식:</strong> 일반적인 가지치기 기법은 전체 네트워크를 먼저 완전히 학습시킨 후, 가중치의 크기(magnitude)가 작은 연결들을 제거하고, 남은 가중치들을 기반으로 모델을 미세 조정(fine-tuning)하는 파이프라인을 따릅니다.</li>
<li><strong>기존 방법의 한계:</strong> 가지치기로 생성된 희소한 네트워크 구조를 처음부터 다시 학습(Train from scratch)시키고자 할 경우, 원래의 네트워크보다 학습 속도가 크게 느려지며 최종 정확도 또한 하락합니다. 즉, 압축된 구조는 추론 시에는 효율적이지만, 학습 단계 자체의 연산량을 줄이는 데는 활용되지 못하는 문제가 있었습니다.</li>
<li><strong>핵심 문제 정의:</strong> 본 연구는 &quot;처음부터 독립적으로 학습시킬 수 있으면서도 원본 모델과 동등한 성능을 내는, 작고 희소한 부분 네트워크(Subnetwork)를 사전에 식별해낼 수 있는가?&quot;라는 문제를 제기하고, 이를 해결하는 복권 가설(Lottery Ticket Hypothesis)을 검증합니다.</li>
</ul>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<ul>
<li><strong>전체 방법의 핵심 아이디어:</strong> 거대하게 과매개변수화(Overparameterized)된 신경망 안에는 초기화 당시부터 학습에 매우 유리한 가중치와 구조의 결합, 즉 &#39;초기화 복권에 당첨된 부분 네트워크(Winning Ticket)&#39;가 숨어 있다는 것입니다.</li>
<li><strong>입력 데이터의 표현 및 전처리 방식:</strong> 입력 데이터 $x$는 전체 파라미터 $\theta$를 가진 피드포워드 신경망 $f(x; \theta)$에 주입됩니다. 본 논문에서는 이진 마스크 $m \in {0, 1}^{|\theta|}$을 도입하여 특정 연결을 활성화 또는 비활성화합니다. 데이터는 물리적으로 삭제된 가중치를 건너뛰고, 요소별 곱 연산이 적용된 형태인 $f(x; m \odot \theta)$ 구조를 통과하며 변환됩니다.</li>
<li><strong>모델 및 알고리즘의 세부 구조:</strong>
단일 단계로 파라미터를 크게 잘라내는 일회성 가지치기(One-shot pruning)보다, $n$회에 걸쳐 점진적으로 잘라내는 반복적 가지치기(Iterative Pruning) 알고리즘을 핵심 메커니즘으로 사용합니다. 이 메커니즘은 다음과 같은 구체적인 학습 및 추론 파이프라인을 따릅니다.
<img src="https://velog.velcdn.com/images/jack_7711/post/3f3987f5-89c7-4250-9f6d-119fb793d42b/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/3b12fe75-1b85-42a7-a4c7-226a6f36249a/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/22e488bb-4182-4db9-bb8b-91f97e79fc32/image.png" alt=""></li>
</ul>
<h2 id="학습training-파이프라인">학습(Training) 파이프라인</h2>
<ol>
<li>신경망 $f(x; \theta_0)$를 무작위로 초기화합니다. (초기 가중치 $\theta_0 \sim D_\theta$)</li>
<li>주어진 훈련 데이터셋에 대해 SGD 또는 Adam 최적화기를 사용하여 $j$ 반복(iterations) 동안 네트워크를 학습시켜 도출된 파라미터 $\theta_j$를 얻습니다.</li>
<li>$\theta_j$에서 가중치 크기가 가장 작은 파라미터 중 $p%$를 가지치기하여 이진 마스크 $m$을 생성합니다.</li>
<li><strong>[핵심 디테일]</strong> 마스크에 의해 살아남은 나머지 파라미터들의 값을 학습된 $\theta_j$가 아닌, 1단계의 초기화 값 $\theta_0$로 완전히 초기화(Reset)합니다. 도출된 $f(x; m \odot \theta_0)$가 당첨 티켓이 되며, 목표한 압축률에 도달할 때까지 2~4단계를 반복합니다.</li>
</ol>
<h2 id="추론inference-파이프라인">추론(Inference) 파이프라인</h2>
<p>학습 파이프라인을 통해 식별된 희소 마스크 $m$과 이에 대응하는 초기화 가중치 집합만을 사용하여 모델을 훈련시킨 후, 추론 단계에서는 가지치기된 빈 공간의 연산을 생략한 $f(x; m \odot \theta)$ 형태로 평가를 수행합니다.</p>
<ul>
<li><strong>기존 방법론과의 기술적 차별성:</strong> 기존 기법은 가지치기 후 &#39;살아남은 현재 가중치 값&#39;을 유지하여 미세 조정을 진행하지만, 본 연구는 &#39;살아남은 연결 구조(마스크 $m$)&#39;만 유지한 채 가중치 값 자체는 <strong>학습 이전의 원본 초기화 값($\theta_0$)으로 반드시 되돌린다</strong>는 점에서 구조적, 이론적으로 명확한 차별성을 가집니다.</li>
</ul>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<ul>
<li><strong>사용된 데이터셋 및 평가 환경:</strong> 완전 연결망(Lenet)은 MNIST 데이터셋에서 평가되었고, 합성곱 신경망(VGG 기반의 Conv-2/4/6, Resnet-18, VGG-19)은 CIFAR10 데이터셋에서 평가되었습니다.</li>
<li><strong>비교 대상 및 실험 세팅:</strong> 제안된 초기화 값을 유지하는 당첨 티켓(Winning Ticket) 방법론과, 구조(마스크 $m$)는 동일하게 유지하되 가중치를 완전히 새로운 무작위 값으로 재초기화(Random Reinit)한 하위 네트워크를 원본 모델(Unpruned Network)과 정량적으로 비교하였습니다.</li>
<li><strong>핵심 성능 결과:</strong> 발견된 당첨 티켓들은 원본 파라미터 수의 10% ~ 20%(혹은 그 이하)에 불과한 크기임에도 불구하고, 원본 네트워크와 동등하거나 최대 3.5%p 더 높은 테스트 정확도를 기록했습니다. 또한, 최소 검증 손실에 도달하는 조기 종료(Early-stopping) 시점이 최대 3.5배 더 빨라졌습니다.</li>
<li><strong>어블레이션 스터디 및 성능 향상 해석:</strong> 당첨 티켓의 구조를 유지한 채 가중치만 무작위로 재초기화한 실험(Random Reinit)에서는 네트워크의 학습 속도가 현저히 느려지고 최종 정확도가 크게 하락했습니다. 이는 부분 신경망의 성능이 단순한 &#39;희소 구조&#39; 덕분이 아니라 &#39;특정 초기화 값&#39;과의 결합에 기인함을 강력하게 증명합니다. 또한 Dropout을 함께 적용했을 때 티켓 추출의 시너지 효과가 발생함을 확인했습니다. 깊은 네트워크(Resnet-18, VGG-19)의 경우 층별(layer-wise) 가지치기 대신 전체 가중치를 기준으로 하는 전역 가지치기(Global pruning)를 적용하고, 높은 학습률에서는 학습률 웜업(Warmup) 스케줄링을 동반해야만 당첨 티켓을 온전히 추출할 수 있음이 실험적으로 해석되었습니다.</li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<ul>
<li><strong>방법의 한계점:</strong></li>
<li><strong>연산량 제약:</strong> 당첨 티켓을 찾기 위한 핵심 기법인 &#39;반복적 가지치기&#39;는 네트워크를 목표 압축률에 도달할 때까지 매번 처음부터 끝까지 재학습시켜야 하므로 탐색 과정의 컴퓨팅 비용이 기하급수적으로 높습니다. 이로 인해 본 논문에서는 Imagenet과 같은 대용량 데이터셋까지 연구를 확장하지 못했습니다.</li>
<li><strong>하드웨어 엔지니어링 한계:</strong> 사용된 가지치기 방식이 가중치 개별 단위의 비구조적 가지치기(Unstructured magnitude pruning)이므로, 이론적인 연산량은 줄어들지만 실제 현대 GPU 하드웨어나 라이브러리 구조상 즉각적인 추론 가속이나 메모리 감소 효과로 직결되지는 않는다는 제약 조건이 존재합니다.</li>
</ul>
<ul>
<li><strong>실제 환경 적용 시 고려 과제:</strong> 깊은 모델 환경에서 당첨 티켓을 찾기 위해서는 학습률 웜업과 같은 섬세한 하이퍼파라미터 튜닝이 필수적이며, 탐색 연산 비용을 줄일 수 있는 One-shot 기법이나 대안적 알고리즘의 개발이 선행되어야 실제 상용 훈련 파이프라인에 적용할 수 있습니다.</li>
<li><strong>연구가 가지는 의미:</strong> 딥러닝 모델이 왜 수많은 파라미터를 가져야만(Overparameterization) 학습이 잘 되는지에 대한 이론적 해답을 제시합니다. 즉, 파라미터가 많을수록 최적의 구조와 가중치를 가진 &#39;당첨 티켓&#39;을 포함할 확률이 높아지기 때문이라는 해석을 가능케 합니다. 이는 차후 학습을 완료하고 압축하는 것이 아니라, 학습 초기 단계부터 극도로 효율적인 희소 네트워크를 훈련시키는 새로운 아키텍처 설계와 최적화 이론의 기반이 됩니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Insight] 네트워크관리사 2급 필기 정리]]></title>
            <link>https://velog.io/@jack_7711/Insight-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EA%B4%80%EB%A6%AC%EC%82%AC-2%EA%B8%89-%ED%95%84%EA%B8%B0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jack_7711/Insight-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EA%B4%80%EB%A6%AC%EC%82%AC-2%EA%B8%89-%ED%95%84%EA%B8%B0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 17 May 2026 03:26:49 GMT</pubDate>
            <description><![CDATA[<h1 id="1-네트워크-기본-개념">1. 네트워크 기본 개념</h1>
<h2 id="osi-7계층">OSI 7계층</h2>
<ul>
<li>FTP는 응용 계층 프로토콜이다.</li>
<li>HTTP는 응용 계층 프로토콜이다.</li>
<li>HTTPS는 TLS를 통해 애플리케이션 계층 데이터를 암호화한다.</li>
<li>SNMP는 응용 계층 프로토콜이다.</li>
<li>IPsec은 OSI 3계층에서 동작한다.</li>
<li>L7 스위치는 응용 계층에서 동작한다.</li>
</ul>
<h2 id="패킷-교환망">패킷 교환망</h2>
<ul>
<li>메시지를 짧은 패킷으로 분할하여 전송한다.</li>
<li>연결 설정 방식에 따라 가상 회선 방식과 데이터그램 방식으로 나뉜다.</li>
<li>회선 차단과 같은 블로킹 현상이 없다.</li>
</ul>
<h2 id="가상-회선-교환-방식">가상 회선 교환 방식</h2>
<ul>
<li>데이터 전송 전에 목적지까지 경로를 설정한다.</li>
<li>설정된 경로를 따라 데이터를 전송한다.</li>
<li>일정 시간 동안 데이터가 없으면 경로를 해제한다.</li>
</ul>
<h2 id="다중화">다중화</h2>
<ul>
<li>여러 신호를 하나의 통신 회선으로 전송하고, 수신 측에서 다시 분리하는 방식이다.</li>
<li>TDM은 전송할 데이터가 없어도 타임 슬롯이 할당되어 대역폭 낭비가 발생할 수 있다.</li>
<li>WDM은 광증폭기를 사용하여 무중계 장거리 전송이 가능하다.</li>
</ul>
<h2 id="전송-왜곡">전송 왜곡</h2>
<ul>
<li>여러 주파수 성분이 서로 다른 지연 시간으로 도달하면 위상 왜곡이 발생한다.</li>
</ul>
<hr>
<h1 id="2-ip-주소와-ip-프로토콜">2. IP 주소와 IP 프로토콜</h1>
<h2 id="ipv4">IPv4</h2>
<ul>
<li>127로 시작하는 주소는 루프백 주소이다.</li>
<li>예: <code>127.0.0.1</code></li>
<li>IPv4 헤더에는 Version, Header Length, Header Checksum이 포함된다.</li>
<li>ACK는 IPv4 헤더에 포함되지 않는다.</li>
</ul>
<h2 id="사설-ip-대역">사설 IP 대역</h2>
<table>
<thead>
<tr>
<th>클래스</th>
<th>범위</th>
</tr>
</thead>
<tbody><tr>
<td>A 클래스</td>
<td>10.0.0.0 ~ 10.255.255.255</td>
</tr>
<tr>
<td>B 클래스</td>
<td>172.16.0.0 ~ 172.31.255.255</td>
</tr>
<tr>
<td>C 클래스</td>
<td>192.168.0.0 ~ 192.168.255.255</td>
</tr>
</tbody></table>
<h2 id="ipv6">IPv6</h2>
<ul>
<li>자동 설정 기능을 지원한다.</li>
<li>주소 표기 시 앞쪽의 0은 생략할 수 있다.</li>
<li>연속된 0은 <code>::</code>으로 한 번만 생략할 수 있다.</li>
<li><code>:::</code>은 사용하지 않는다.</li>
<li>Hop Limit은 데이터그램의 생존 기간과 관련된다.</li>
<li>Fragmentation 확장 헤더는 큰 패킷을 단편화할 때 사용된다.</li>
<li>ICMPv6의 Neighbor Solicitation / Advertisement는 IPv4의 ARP 역할을 수행한다.</li>
</ul>
<h2 id="ip-프로토콜-역할">IP 프로토콜 역할</h2>
<ul>
<li>MTU보다 큰 데이터그램은 단편화한다.</li>
</ul>
<hr>
<h1 id="3-tcp--udp--icmp--igmp">3. TCP / UDP / ICMP / IGMP</h1>
<h2 id="tcp">TCP</h2>
<ul>
<li>연결 지향형 전송 방식이다.</li>
<li>신뢰성 있는 전송을 제공한다.</li>
<li>오류 제어와 흐름 제어를 제공한다.</li>
<li>3-way Handshaking을 통해 연결을 설정한다.</li>
<li>Sliding Window 방식을 사용한다.</li>
<li>종단 간 흐름 제어를 위해 Dynamic Sliding Window 방식을 사용한다.</li>
</ul>
<h2 id="tcp-플래그">TCP 플래그</h2>
<table>
<thead>
<tr>
<th>플래그</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>SYN</td>
<td>연결 요청</td>
</tr>
<tr>
<td>ACK</td>
<td>확인 응답</td>
</tr>
<tr>
<td>FIN</td>
<td>정상 연결 종료</td>
</tr>
</tbody></table>
<h2 id="tcp-헤더-필드-길이">TCP 헤더 필드 길이</h2>
<table>
<thead>
<tr>
<th>필드</th>
<th>길이</th>
</tr>
</thead>
<tbody><tr>
<td>Source Port Address</td>
<td>16비트</td>
</tr>
<tr>
<td>Sequence Number</td>
<td>32비트</td>
</tr>
<tr>
<td>Flags</td>
<td>9비트</td>
</tr>
</tbody></table>
<h2 id="tcp-3-way-handshake">TCP 3-way Handshake</h2>
<table>
<thead>
<tr>
<th>단계</th>
<th>동작</th>
<th>클라이언트 상태</th>
<th>서버 상태</th>
</tr>
</thead>
<tbody><tr>
<td>시작</td>
<td>서버가 연결 요청 대기</td>
<td>CLOSED</td>
<td>LISTEN</td>
</tr>
<tr>
<td>1단계</td>
<td>클라이언트가 SYN 전송</td>
<td>SYN_SENT</td>
<td>LISTEN</td>
</tr>
<tr>
<td>2단계</td>
<td>서버가 SYN+ACK 전송</td>
<td>SYN_SENT</td>
<td>SYN_RECEIVED</td>
</tr>
<tr>
<td>3단계</td>
<td>클라이언트가 ACK 전송</td>
<td>ESTABLISHED</td>
<td>SYN_RECEIVED</td>
</tr>
<tr>
<td>완료</td>
<td>서버가 ACK 수신</td>
<td>ESTABLISHED</td>
<td>ESTABLISHED</td>
</tr>
</tbody></table>
<h2 id="udp">UDP</h2>
<ul>
<li>비연결형 전송 방식이다.</li>
<li>TCP보다 신뢰성이 낮다.</li>
<li>패킷 순서 보장, 재조립, 재전송을 제공하지 않는다.</li>
<li>데이터 단위는 사용자 데이터그램이다.</li>
<li>UDP 헤더에는 Source Port, Destination Port, Checksum이 포함된다.</li>
</ul>
<h2 id="icmp">ICMP</h2>
<ul>
<li>IP 데이터그램 처리 중 발생하는 오류를 보고한다.</li>
<li>네트워크 장비 간 오류 상황을 공유할 수 있다.</li>
<li>ICMPv4에는 질의 메시지가 있다.</li>
<li>목적지 도달 불가, TTL 0, 헤더 오류 등의 상황에서 사용된다.</li>
</ul>
<h2 id="icmp-message-type">ICMP Message Type</h2>
<table>
<thead>
<tr>
<th>Type</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>Echo Reply</td>
</tr>
<tr>
<td>4</td>
<td>Source Quench / 흐름 제어 관련</td>
</tr>
<tr>
<td>5</td>
<td>Redirect</td>
</tr>
<tr>
<td>8</td>
<td>Echo Request</td>
</tr>
<tr>
<td>13</td>
<td>Timestamp Request</td>
</tr>
<tr>
<td>17</td>
<td>Address Mask Request</td>
</tr>
</tbody></table>
<h2 id="igmp">IGMP</h2>
<ul>
<li>멀티캐스트 그룹 가입과 탈퇴에 사용된다.</li>
<li>스트리밍 채널 변경 시 그룹 가입·탈퇴 신호를 전달한다.</li>
<li>TTL을 제공한다.</li>
<li>IGMPv1에서는 첫 보고 메시지 손실 시 재전송되지 않는다.</li>
<li>호스트와 라우터 간 비대칭 통신 구조를 가진다.</li>
</ul>
<hr>
<h1 id="4-dns">4. DNS</h1>
<h2 id="dns-기본-개념">DNS 기본 개념</h2>
<ul>
<li>도메인 이름을 IP 주소로 변환한다.</li>
<li>TCP와 UDP 포트를 모두 사용한다.</li>
<li>호스트 이름에 대한 분산 데이터베이스이다.</li>
<li>캐싱을 통해 이전 도메인-IP 대응 정보를 저장한다.</li>
<li>여러 IP 주소를 반환하여 부하 분산에 활용할 수 있다.</li>
</ul>
<h2 id="etchosts"><code>/etc/hosts</code></h2>
<ul>
<li>로컬 DNS처럼 사용할 수 있는 파일이다.</li>
<li>그룹웨어 주소를 직접 매핑하고 싶을 때 수정할 수 있다.</li>
</ul>
<h2 id="dns-레코드">DNS 레코드</h2>
<table>
<thead>
<tr>
<th>레코드</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>SOA</td>
<td>Zone 파일의 첫 번째 레코드</td>
</tr>
<tr>
<td>CNAME</td>
<td>실제 도메인 이름과 연결되는 가상 도메인 이름</td>
</tr>
<tr>
<td>PTR</td>
<td>역방향 조회</td>
</tr>
<tr>
<td>TTL</td>
<td>DNS 캐시 유지 시간</td>
</tr>
</tbody></table>
<h2 id="soa-레코드">SOA 레코드</h2>
<ul>
<li>Zone 파일은 항상 SOA로 시작한다.</li>
<li>해당 Zone의 기본 정보가 저장된다.</li>
<li>시리얼 값으로 Zone 파일 갱신 여부를 확인한다.</li>
<li>Refresh는 주 서버와 보조 서버의 동기화 주기를 의미한다.</li>
</ul>
<h2 id="dns-ttl">DNS TTL</h2>
<ul>
<li>DNS 레코드가 캐시에 유지되는 시간이다.</li>
<li>너무 짧으면 DNS 쿼리가 많아져 서버 부하가 증가한다.</li>
<li>너무 길면 IP 변경 시 갱신이 늦어진다.</li>
</ul>
<h2 id="dnssec">DNSSEC</h2>
<ul>
<li>DNS 응답의 무결성과 출처 인증을 제공한다.</li>
</ul>
<hr>
<h1 id="5-주요-프로토콜과-포트">5. 주요 프로토콜과 포트</h1>
<h2 id="ssh">SSH</h2>
<ul>
<li>기본 포트는 22번이다.</li>
<li>데이터 암호화 전송을 제공한다.</li>
<li>데이터 무결성을 제공한다.</li>
<li>공개키 암호화 방식을 사용한다.</li>
<li>Telnet보다 보안성이 높다.</li>
<li>SSH-1은 RSA 암호화를 사용한다.</li>
<li>SSH-2는 RSA 외에도 다양한 키 교환 방식을 지원한다.</li>
<li>포트 번호를 변경하면 외부 공격을 줄이는 데 도움이 된다.</li>
</ul>
<h2 id="http--https">HTTP / HTTPS</h2>
<ul>
<li>HTTP 기본 포트는 80번이다.</li>
<li>HTTPS 기본 포트는 443번이다.</li>
<li>HTTPS는 TLS를 통해 데이터를 암호화한다.</li>
<li>HTTP/2는 SPDY 기반이며 TCP 연결을 사용한다.</li>
</ul>
<h2 id="ftp">FTP</h2>
<ul>
<li>파일 송수신에 사용된다.</li>
<li>FTP 세션이 설정되면 원격 파일 복사가 가능하다.</li>
<li>제어 채널과 데이터 채널을 사용한다.</li>
<li>데이터 채널은 파일 송수신 요청이 있을 때마다 새로 설정된다.</li>
<li>FTP 서버는 데이터 채널 연결 시 20번 포트를 사용한다.</li>
</ul>
<h2 id="tftp">TFTP</h2>
<ul>
<li>UDP 기반으로 동작한다.</li>
<li>데이터 전송 중 손실 가능성이 있다.</li>
</ul>
<h2 id="smtp--pop3">SMTP / POP3</h2>
<table>
<thead>
<tr>
<th>프로토콜</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td>SMTP</td>
<td>메일 송신</td>
</tr>
<tr>
<td>POP3</td>
<td>메일 수신</td>
</tr>
</tbody></table>
<h2 id="snmp">SNMP</h2>
<ul>
<li>네트워크 장비 상태와 관리 정보를 수집한다.</li>
<li>UDP 기반 프로토콜이다.</li>
<li>응용 계층 프로토콜이다.</li>
<li>RFC 1157에 규정되어 있다.</li>
</ul>
<h2 id="sntp">SNTP</h2>
<ul>
<li>네트워크 장비의 시간 동기화에 사용된다.</li>
<li>포트 123을 사용한다.</li>
</ul>
<h2 id="sip">SIP</h2>
<ul>
<li>음성·화상 같은 멀티미디어 세션을 생성, 수정, 종료한다.</li>
<li>TCP와 UDP를 모두 사용할 수 있다.</li>
<li>SIP URI를 사용한다.</li>
<li>IP 주소에 종속되지 않고 서비스를 제공할 수 있다.</li>
</ul>
<hr>
<h1 id="6-라우팅과-스위칭">6. 라우팅과 스위칭</h1>
<h2 id="l2-스위치">L2 스위치</h2>
<ul>
<li>목적지 MAC 주소를 확인하여 프레임을 전송한다.</li>
</ul>
<h2 id="l4-스위치">L4 스위치</h2>
<ul>
<li>TCP/UDP 포트를 기반으로 트래픽을 처리한다.</li>
<li>로드 밸런싱을 수행한다.</li>
<li>서버 상태 확인을 위한 Health Check 기능이 있다.</li>
<li>NAT 기능을 제공할 수 있다.</li>
<li>외부 요청은 L4 스위치를 거쳐 서버로 전달될 수 있다.</li>
</ul>
<h2 id="l7-스위치">L7 스위치</h2>
<ul>
<li>응용 계층에서 동작한다.</li>
<li>IP, 포트뿐만 아니라 L5~L7 패킷 정보까지 확인한다.</li>
<li>L2/L3/L4 기능을 포함할 수 있다.</li>
</ul>
<h2 id="load-balancing">Load Balancing</h2>
<ul>
<li>서버 부하를 분산하는 기술이다.</li>
<li>Round Robin은 장비에 순차적으로 트래픽을 분산하는 방식이다.</li>
</ul>
<h2 id="nat">NAT</h2>
<ul>
<li>사설 IP를 공인 IP로 변환하는 기술이다.</li>
<li>DHCP와 혼동하지 않아야 한다.</li>
</ul>
<h2 id="rip">RIP</h2>
<ul>
<li>거리 벡터 라우팅 프로토콜이다.</li>
<li>Bellman-Ford 알고리즘을 사용한다.</li>
<li>경로 선택 기준은 Hop Count이다.</li>
<li>최대 홉 수는 15홉이다.</li>
<li>16홉은 도달 불가를 의미한다.</li>
<li>인접 라우터가 알려주는 거리 정보를 바탕으로 경로를 선택한다.</li>
<li>주기적으로 라우팅 정보를 업데이트한다.</li>
<li>소규모 네트워크에 적합하다.</li>
<li>수렴 속도가 느린 편이다.</li>
</ul>
<h2 id="ospf">OSPF</h2>
<ul>
<li>링크 상태 라우팅 프로토콜이다.</li>
<li>Dijkstra 알고리즘, 즉 SPF 알고리즘을 사용한다.</li>
<li>경로 선택 기준은 Cost이다.</li>
<li>Cost는 일반적으로 대역폭을 기준으로 계산된다.</li>
<li>라우터들이 자신의 링크 상태 정보를 공유한다.</li>
<li>각 라우터는 전체 네트워크 토폴로지를 바탕으로 최단 경로를 계산한다.</li>
<li>Hello 패킷으로 이웃 라우터 상태를 확인한다.</li>
<li>변화 발생 시 라우팅 정보를 갱신한다.</li>
<li>중대형 네트워크에 적합하다.</li>
<li>수렴 속도가 빠른 편이다.</li>
<li>IP 버전에 따라 사용하는 OSPF 버전이 다르다.</li>
</ul>
<h2 id="rip-vs-ospf">RIP vs OSPF</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>RIP</th>
<th>OSPF</th>
</tr>
</thead>
<tbody><tr>
<td>라우팅 방식</td>
<td>거리 벡터</td>
<td>링크 상태</td>
</tr>
<tr>
<td>사용 알고리즘</td>
<td>Bellman-Ford</td>
<td>Dijkstra / SPF</td>
</tr>
<tr>
<td>경로 판단 기준</td>
<td>Hop Count</td>
<td>Cost</td>
</tr>
<tr>
<td>최대 홉 수</td>
<td>15홉</td>
<td>제한 없음에 가까움</td>
</tr>
<tr>
<td>16홉 의미</td>
<td>도달 불가</td>
<td>해당 없음</td>
</tr>
<tr>
<td>라우팅 정보</td>
<td>인접 라우터의 거리 정보</td>
<td>전체 네트워크 링크 상태</td>
</tr>
<tr>
<td>업데이트 방식</td>
<td>주기적 업데이트</td>
<td>변화 발생 시 중심</td>
</tr>
<tr>
<td>수렴 속도</td>
<td>느림</td>
<td>빠름</td>
</tr>
<tr>
<td>적합한 규모</td>
<td>소규모</td>
<td>중대형</td>
</tr>
<tr>
<td>프로토콜 성격</td>
<td>Distance Vector</td>
<td>Link State</td>
</tr>
</tbody></table>
<h2 id="bellman-ford-알고리즘">Bellman-Ford 알고리즘</h2>
<ul>
<li>RIP에서 사용된다.</li>
<li>Distance Vector Routing Protocol에서 사용된다.</li>
<li>인접 라우터가 알려주는 거리 정보를 바탕으로 최단 경로를 계산한다.</li>
<li>OSPF에서는 사용되지 않는다.</li>
<li>OSPF는 Bellman-Ford가 아니라 Dijkstra 알고리즘을 사용한다.</li>
</ul>
<h2 id="stp">STP</h2>
<ul>
<li>네트워크 루프를 방지하는 프로토콜이다.</li>
</ul>
<hr>
<h1 id="7-vlan--vtp--트렁크">7. VLAN / VTP / 트렁크</h1>
<h2 id="vlan">VLAN</h2>
<ul>
<li>하나의 물리적 네트워크를 논리적으로 분리한다.</li>
<li>여러 스위치에 걸쳐 구성할 수 있다.</li>
</ul>
<h2 id="trunk">Trunk</h2>
<ul>
<li>스위치 간 VLAN 정보를 전달하기 위한 인터페이스이다.</li>
</ul>
<h2 id="vtp">VTP</h2>
<ul>
<li>VLAN 정보를 스위치 간에 관리·전파하는 프로토콜이다.</li>
</ul>
<table>
<thead>
<tr>
<th>모드</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>Server mode</td>
<td>VLAN 생성, 수정, 삭제 가능</td>
</tr>
<tr>
<td>Client mode</td>
<td>VLAN 정보 수신</td>
</tr>
<tr>
<td>Transparent mode</td>
<td>VLAN 정보를 전달하지만 직접 반영하지 않음</td>
</tr>
</tbody></table>
<hr>
<h1 id="8-무선-네트워크">8. 무선 네트워크</h1>
<h2 id="ieee-80211">IEEE 802.11</h2>
<ul>
<li>802.11ax는 OFDMA, DL/UL MU-MIMO 등을 지원한다.</li>
<li>고해상도 스트리밍, AR/VR, 온라인 게임 같은 고대역폭 서비스에 적합하다.</li>
</ul>
<h2 id="csmaca">CSMA/CA</h2>
<ul>
<li>무선 LAN에서 사용하는 매체 접근 제어 방식이다.</li>
<li>송신 전 채널을 확인한다.</li>
<li>필요 시 랜덤 백오프를 수행한다.</li>
<li>RTS/CTS를 사용할 수 있다.</li>
</ul>
<h2 id="csmacd">CSMA/CD</h2>
<ul>
<li>유선 LAN의 버스 구조에서 사용된다.</li>
<li>채널 사용 여부를 확인한 뒤 데이터를 전송한다.</li>
<li>충돌이 발생하면 데이터를 폐기하고 일정 시간 후 재전송한다.</li>
</ul>
<h2 id="wpan">WPAN</h2>
<ul>
<li>10m 이내의 짧은 거리에서 장치 간 통신을 지원한다.</li>
<li>ZigBee, RFID, Bluetooth, UWB 등이 포함된다.</li>
</ul>
<h2 id="zigbee">ZigBee</h2>
<ul>
<li>저전력, 저비용 근거리 무선 네트워크 기술이다.</li>
<li>IEEE 802.15.4의 PHY 계층과 MAC 계층을 기반으로 한다.</li>
</ul>
<h2 id="mesh-network">Mesh Network</h2>
<ul>
<li>노드 이동이 자유롭다.</li>
<li>토폴로지가 동적으로 변한다.</li>
<li>다중 홉 라우팅을 사용한다.</li>
<li>하나의 연결이 끊어져도 다른 경로로 전송할 수 있다.</li>
</ul>
<h2 id="wireless-mesh-network">Wireless Mesh Network</h2>
<ul>
<li>장치들이 직접 데이터 통신 주체가 된다.</li>
<li>다른 장치의 트래픽을 릴레이하고 라우팅한다.</li>
<li>유선망 없이 망 확장이 용이하다.</li>
</ul>
<hr>
<h1 id="9-vpn--보안--웹-보안">9. VPN / 보안 / 웹 보안</h1>
<h2 id="vpn">VPN</h2>
<ul>
<li>인터넷상에서 가상 경로를 설정해 안전한 통신을 제공한다.</li>
<li>Tunneling을 사용한다.</li>
</ul>
<h2 id="ipsec">IPsec</h2>
<ul>
<li>OSI 3계층에서 동작한다.</li>
<li>전송 모드와 터널 모드를 사용한다.</li>
<li>전송 모드는 IP 페이로드만 보호한다.</li>
<li>터널 모드는 원본 IP 패킷 전체를 새 IP 헤더로 캡슐화한다.</li>
</ul>
<h2 id="waf">WAF</h2>
<ul>
<li>웹 서버를 보호하는 보안 장비이다.</li>
<li>HTTP, HTTPS 기반 공격을 방어한다.</li>
<li>NAC는 비인가 단말 접근 차단 장비이므로 구분해야 한다.</li>
</ul>
<h2 id="https">HTTPS</h2>
<ul>
<li>TLS를 통해 데이터를 암호화한다.</li>
<li>기본 포트는 443번이다.</li>
</ul>
<h2 id="well-known-port">Well-known Port</h2>
<ul>
<li>1번부터 1023번까지 사용한다.</li>
<li>Apache 웹 서버를 Well-known Port로 실행하려면 관리자 권한이 필요하다.</li>
<li>포트 변경 시 다른 서비스와 충돌하지 않아야 한다.</li>
</ul>
<hr>
<h1 id="10-전송-제어와-오류-제어">10. 전송 제어와 오류 제어</h1>
<h2 id="흐름-제어">흐름 제어</h2>
<ul>
<li>Stop and Wait</li>
<li>XON/XOFF</li>
<li>Sliding Window</li>
</ul>
<h2 id="오류-제어">오류 제어</h2>
<ul>
<li>Stop and Wait ARQ</li>
<li>Go-Back-N ARQ</li>
<li>Selective Repeat ARQ</li>
</ul>
<h2 id="adaptive-arq">Adaptive ARQ</h2>
<ul>
<li>전송 효율을 높이기 위해 프레임 길이를 동적으로 변경하는 ARQ 방식이다.</li>
</ul>
<hr>
<h1 id="11-이더넷과-네트워크-장비">11. 이더넷과 네트워크 장비</h1>
<h2 id="gigabit-ethernet">Gigabit Ethernet</h2>
<ul>
<li>1000BASE-SX는 광케이블을 사용하는 기가비트 이더넷 규격이다.</li>
<li>1000BASE-T는 UTP 케이블을 사용한다.</li>
<li>1000BASE-T는 주로 스타형 토폴로지에서 사용된다.</li>
<li>IEEE 802.3ab 규격이다.</li>
</ul>
<h2 id="token-ring">Token Ring</h2>
<ul>
<li>각 노드에 전송 기회를 순차적으로 부여하는 MAC 방식이다.</li>
<li>모든 노드가 공평하게 데이터를 전송할 수 있다.</li>
</ul>
<h2 id="star-topology">Star Topology</h2>
<ul>
<li>중앙 장치를 중심으로 point-to-point 방식으로 연결한다.</li>
<li>중앙 장치를 통해 데이터를 교환한다.</li>
<li>중앙 장치 장애 시 전체 통신망에 영향을 줄 수 있다.</li>
</ul>
<hr>
<h1 id="12-클라우드--가상화--스토리지">12. 클라우드 / 가상화 / 스토리지</h1>
<h2 id="클라우드-컴퓨팅">클라우드 컴퓨팅</h2>
<ul>
<li>사용자는 필요한 만큼 컴퓨팅 자원을 사용할 수 있다.</li>
<li>자원은 동적으로 할당·재할당된다.</li>
<li>사용량 기반 미터링이 가능하다.</li>
<li>통신 환경에 따라 서비스 품질이 영향을 받을 수 있다.</li>
<li>데이터의 물리적 위치를 알기 어렵다는 단점이 있다.</li>
</ul>
<h2 id="클라우드-배포-모델">클라우드 배포 모델</h2>
<table>
<thead>
<tr>
<th>모델</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>Public Cloud</td>
<td>외부 제공자가 관리</td>
</tr>
<tr>
<td>Private Cloud</td>
<td>조직 내부 전용</td>
</tr>
<tr>
<td>Hybrid Cloud</td>
<td>공용 + 사설 혼합</td>
</tr>
</tbody></table>
<h2 id="nfv">NFV</h2>
<ul>
<li>네트워크 기능을 소프트웨어로 가상화하는 기술이다.</li>
<li>NFVI는 물리 자원, 가상화 지원 기능, VNF 실행 환경을 제공한다.</li>
<li>네트워크 장비 기능을 소프트웨어로 분리하여 제어·관리할 수 있다.</li>
</ul>
<h2 id="san">SAN</h2>
<ul>
<li>중앙 저장소를 공유하여 저장 공간 활용도를 높인다.</li>
<li>대규모 환경에서 사용된다.</li>
<li>파이버 채널 기반으로 빠른 데이터 접근이 가능하다.</li>
<li>백업과 복구에 유리하다.</li>
</ul>
<h2 id="raid">RAID</h2>
<table>
<thead>
<tr>
<th>RAID</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>RAID 0</td>
<td>스트라이핑, 속도 빠름, 2개 이상 디스크 필요</td>
</tr>
<tr>
<td>RAID 5</td>
<td>회전 패리티 방식, 병목 감소</td>
</tr>
</tbody></table>
<ul>
<li>데이터를 다수의 하드디스크에 병렬 전송해 전송 속도를 높일 수 있다.</li>
<li>동일 데이터를 다른 위치에 중복 저장할 수 있다.</li>
<li>장애 발생 시 시스템 정지 없이 디스크 교체가 가능하다.</li>
</ul>
<h2 id="windows-containers">Windows Containers</h2>
<ul>
<li>가벼운 가상화 기술이다.</li>
<li>Hyper-V 가상머신보다 가볍게 생성하고 운영할 수 있다.</li>
<li>Hyper-V는 완전한 OS를 포함하는 독립된 컴퓨터에 가깝다.</li>
</ul>
<hr>
<h1 id="13-linux-기본-개념">13. Linux 기본 개념</h1>
<h2 id="주요-디렉터리">주요 디렉터리</h2>
<table>
<thead>
<tr>
<th>디렉터리</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>/etc</code></td>
<td>환경설정과 사용자 정보 저장</td>
</tr>
<tr>
<td><code>/var</code></td>
<td>로그 파일과 메일 저장</td>
</tr>
<tr>
<td><code>/proc</code></td>
<td>프로세스 상태, 하드웨어 정보, 시스템 정보 확인</td>
</tr>
<tr>
<td><code>/etc/fstab</code></td>
<td>부팅 시 자동 마운트 항목과 옵션 정의</td>
</tr>
<tr>
<td><code>/etc/passwd</code></td>
<td>사용자 계정 정보 저장</td>
</tr>
</tbody></table>
<h2 id="etcpasswd-구조"><code>/etc/passwd</code> 구조</h2>
<p>예시:</p>
<pre><code class="language-bash">user1:x:500:500::/home/user1:/bin/bash</code></pre>
<table>
<thead>
<tr>
<th>항목</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>user1</td>
<td>사용자 계정명</td>
</tr>
<tr>
<td>x</td>
<td>패스워드는 <code>/etc/shadow</code>에 저장</td>
</tr>
<tr>
<td>500</td>
<td>UID</td>
</tr>
<tr>
<td>500</td>
<td>GID</td>
</tr>
<tr>
<td>빈 값</td>
<td>사용자 설명 정보</td>
</tr>
<tr>
<td><code>/home/user1</code></td>
<td>홈 디렉터리</td>
</tr>
<tr>
<td><code>/bin/bash</code></td>
<td>기본 shell</td>
</tr>
</tbody></table>
<h2 id="shell">Shell</h2>
<ul>
<li>사용자가 입력한 명령어를 Kernel에 전달하는 역할을 한다.</li>
</ul>
<h2 id="grub">GRUB</h2>
<ul>
<li>Linux의 부트 로더이다.</li>
<li>Linux뿐 아니라 다른 운영체제와의 멀티부팅도 지원한다.</li>
</ul>
<hr>
<h1 id="14-linux-명령어">14. Linux 명령어</h1>
<h2 id="파일--권한--검색">파일 / 권한 / 검색</h2>
<table>
<thead>
<tr>
<th>명령어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>chmod -R</code></td>
<td>하위 디렉터리와 파일까지 권한 적용</td>
</tr>
<tr>
<td><code>find -exec</code></td>
<td>찾은 파일에 추가 명령 실행</td>
</tr>
<tr>
<td><code>lsattr</code></td>
<td>파일 속성 확인</td>
</tr>
<tr>
<td><code>cat exam.txt | more</code></td>
<td>파일 내용을 한 페이지씩 출력</td>
</tr>
<tr>
<td><code>x</code></td>
<td>vi에서 문자 하나 삭제</td>
</tr>
</tbody></table>
<h2 id="디스크--파일시스템">디스크 / 파일시스템</h2>
<table>
<thead>
<tr>
<th>명령어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>gdisk</code></td>
<td>2TB 이상 디스크 GPT 파티셔닝</td>
</tr>
<tr>
<td><code>du</code></td>
<td>디스크 사용량 확인</td>
</tr>
<tr>
<td><code>df</code></td>
<td>파일시스템 남은 용량 확인</td>
</tr>
<tr>
<td><code>fdisk</code></td>
<td>파티션 생성·삭제·확인</td>
</tr>
<tr>
<td><code>fsck</code></td>
<td>파일시스템 점검·복구</td>
</tr>
</tbody></table>
<h2 id="사용자--보안">사용자 / 보안</h2>
<table>
<thead>
<tr>
<th>명령어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>lastb</code></td>
<td>비인가 로그인 시도 이력 확인</td>
</tr>
<tr>
<td><code>useradd -g icqa network</code></td>
<td>network 사용자를 icqa 기본 그룹에 추가</td>
</tr>
<tr>
<td><code>chage</code></td>
<td>계정 암호 정책 변경</td>
</tr>
</tbody></table>
<p>예시:</p>
<pre><code class="language-bash">sudo chage -m 2 -M 100 -W 10 -l 10 -E 2026-12-25 John</code></pre>
<ul>
<li><code>-m 2</code>: 최소 2일 후 암호 변경 가능</li>
<li><code>-M 100</code>: 최대 100일 사용 가능</li>
<li><code>-W 10</code>: 만료 10일 전 경고</li>
<li><code>-E 2026-12-25</code>: 계정 만료일</li>
</ul>
<h2 id="프로세스--부팅">프로세스 / 부팅</h2>
<table>
<thead>
<tr>
<th>명령어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>init 6</code></td>
<td>시스템 재부팅</td>
</tr>
<tr>
<td><code>crontab -r</code></td>
<td>crontab 삭제</td>
</tr>
</tbody></table>
<h2 id="crontab">crontab</h2>
<p>매주 월요일 오전 10시에 실행:</p>
<pre><code class="language-bash">0 10 * * 1 /etc/check.sh</code></pre>
<h2 id="리다이렉션">리다이렉션</h2>
<pre><code class="language-bash">ls -al &gt; output.txt</code></pre>
<ul>
<li><code>ls -al</code> 결과를 <code>output.txt</code>에 저장한다.</li>
<li>기존 내용은 덮어쓴다.</li>
<li>append는 아니다.</li>
</ul>
<hr>
<h1 id="15-linux-서버--apache--bind">15. Linux 서버 / Apache / BIND</h1>
<h2 id="apache">Apache</h2>
<table>
<thead>
<tr>
<th>설정</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>LimitRequestBody</code></td>
<td>POST 요청 크기 제한</td>
</tr>
<tr>
<td><code>KeepAliveTimeout 80</code></td>
<td>80초 동안 추가 요청 없으면 연결 종료</td>
</tr>
<tr>
<td><code>Listen 8081</code></td>
<td>웹 서버 포트 설정</td>
</tr>
</tbody></table>
<p>※ 포트를 8001로 변경하려면 일반적으로 <code>Listen 8001</code>로 설정한다.</p>
<h2 id="bind">BIND</h2>
<table>
<thead>
<tr>
<th>명령어 / 파일</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>rpm -qa | grep bind</code></td>
<td>BIND 설치 여부 확인</td>
</tr>
<tr>
<td><code>named-checkconf</code></td>
<td><code>/etc/named.conf</code> 오류 확인</td>
</tr>
<tr>
<td><code>/etc/named.conf</code></td>
<td>BIND 설정 파일</td>
</tr>
<tr>
<td><code>iptables</code></td>
<td>방화벽 설정</td>
</tr>
</tbody></table>
<hr>
<h1 id="16-windows-server">16. Windows Server</h1>
<h2 id="windows-server-기능">Windows Server 기능</h2>
<ul>
<li>Resource Monitor는 CPU, 메모리, 네트워크, 디스크 사용량을 실시간 모니터링한다.</li>
<li>IIS 로그 파일 저장 위치는 변경 가능하다.</li>
<li>Windows Server 2016은 기본적으로 Administrator, DefaultAccount, Guest 계정을 생성한다.</li>
</ul>
<h2 id="active-directory">Active Directory</h2>
<ul>
<li>유니버설 그룹은 포리스트 전체에서 사용할 수 있다.</li>
<li>여러 도메인에서 사용자나 다른 그룹을 포함할 수 있다.</li>
<li>서로 다른 도메인 간 인증과 권한 부여를 위해 트러스트 설정이 필요하다.</li>
</ul>
<h2 id="도메인-사용자-관리-명령어">도메인 사용자 관리 명령어</h2>
<table>
<thead>
<tr>
<th>명령어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>dsadd</code></td>
<td>계정 생성</td>
</tr>
<tr>
<td><code>dsrm</code></td>
<td>계정 삭제</td>
</tr>
<tr>
<td><code>dsmod</code></td>
<td>계정 수정</td>
</tr>
</tbody></table>
<h2 id="iis">IIS</h2>
<ul>
<li>IIS 관리자 실행 명령어:</li>
</ul>
<pre><code class="language-bash">inetmgr.exe</code></pre>
<ul>
<li>요청 필터링을 통해 특정 요청을 차단할 수 있다.</li>
</ul>
<h2 id="windows-실행-명령어">Windows 실행 명령어</h2>
<table>
<thead>
<tr>
<th>명령어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>devmgmt.msc</code></td>
<td>장치 관리자</td>
</tr>
<tr>
<td><code>gpedit.msc</code></td>
<td>로컬 그룹 정책 편집기</td>
</tr>
<tr>
<td><code>perfmon</code></td>
<td>성능 모니터</td>
</tr>
</tbody></table>
<h2 id="ip-갱신">IP 갱신</h2>
<pre><code class="language-bash">ipconfig /renew</code></pre>
<ul>
<li>DHCP로부터 새로운 IP 주소를 재할당받는다.</li>
</ul>
<h2 id="powershell">PowerShell</h2>
<ul>
<li>기존 DOS 명령을 사용할 수 있다.</li>
<li>콘솔에서 대화형으로 사용할 수 있다.</li>
<li>스크립트는 텍스트로 구성된다.</li>
<li>대소문자를 구분하지 않는다.</li>
</ul>
<hr>
<h1 id="17-네트워크-진단-명령어">17. 네트워크 진단 명령어</h1>
<h2 id="netstat">netstat</h2>
<table>
<thead>
<tr>
<th>옵션</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>-b</code></td>
<td>열린 포트와 관련된 실행 파일 확인</td>
</tr>
<tr>
<td><code>-r</code></td>
<td>라우팅 테이블 표시</td>
</tr>
<tr>
<td><code>-p</code></td>
<td>PID와 사용 중인 프로그램명 출력</td>
</tr>
<tr>
<td><code>-a</code></td>
<td>모든 연결 및 수신 대기 포트 표시</td>
</tr>
</tbody></table>
<h2 id="pathping">pathping</h2>
<ul>
<li><code>tracert</code>와 유사한 경로 정보를 제공한다.</li>
<li>홉별 시간과 세부 정보를 추가로 확인할 수 있다.</li>
</ul>
<hr>
<h1 id="18-웹--서버-응답-코드">18. 웹 / 서버 응답 코드</h1>
<h2 id="http-상태-코드">HTTP 상태 코드</h2>
<table>
<thead>
<tr>
<th>코드</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>403</td>
<td>서버가 요청을 거부함. 사용자가 해당 콘텐츠에 접근할 권한이 없음</td>
</tr>
</tbody></table>
<h2 id="wap">WAP</h2>
<ul>
<li>내부 웹 리소스를 인터넷에 게시하는 데 사용된다.</li>
<li>DirectAccess나 VPN처럼 원격 컴퓨터를 네트워크에 직접 연결하는 용도는 아니다.</li>
</ul>
<hr>
<h1 id="19-네트워크-구성-방식">19. 네트워크 구성 방식</h1>
<h2 id="mesh형-네트워크">Mesh형 네트워크</h2>
<ul>
<li>노드의 이동이 자유롭다.</li>
<li>네트워크 토폴로지가 동적으로 변한다.</li>
<li>일대일 다중 홉 라우팅 방식을 사용한다.</li>
<li>하나의 연결이 끊어져도 다른 경로로 전송할 수 있다.</li>
</ul>
<h2 id="star형-네트워크">Star형 네트워크</h2>
<ul>
<li>Point-to-point 방식으로 회선을 연결한다.</li>
<li>각 단말 장치는 중앙 컴퓨터를 통해 데이터를 교환한다.</li>
<li>중앙 장치 장애 시 전체 통신망에 영향을 줄 수 있다.</li>
</ul>
<hr>
<h1 id="20-시험에서-자주-헷갈리는-구분">20. 시험에서 자주 헷갈리는 구분</h1>
<h2 id="nat-vs-dhcp">NAT vs DHCP</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>NAT</td>
<td>사설 IP를 공인 IP로 변환</td>
</tr>
<tr>
<td>DHCP</td>
<td>IP 주소 자동 할당</td>
</tr>
</tbody></table>
<h2 id="waf-vs-nac">WAF vs NAC</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>WAF</td>
<td>웹 서버 공격 방어</td>
</tr>
<tr>
<td>NAC</td>
<td>비인가 단말 접근 차단</td>
</tr>
</tbody></table>
<h2 id="csmaca-vs-csmacd">CSMA/CA vs CSMA/CD</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>CSMA/CA</td>
<td>무선 LAN, 충돌 회피</td>
</tr>
<tr>
<td>CSMA/CD</td>
<td>유선 LAN, 충돌 감지</td>
</tr>
</tbody></table>
<h2 id="l4-vs-l7-스위치">L4 vs L7 스위치</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>기준</th>
</tr>
</thead>
<tbody><tr>
<td>L4</td>
<td>TCP/UDP 포트 기반 처리</td>
</tr>
<tr>
<td>L7</td>
<td>응용 계층 정보까지 분석</td>
</tr>
</tbody></table>
<h2 id="smtp-vs-pop3">SMTP vs POP3</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td>SMTP</td>
<td>메일 송신</td>
</tr>
<tr>
<td>POP3</td>
<td>메일 수신</td>
</tr>
</tbody></table>
<h2 id="dns-cname-vs-ptr">DNS CNAME vs PTR</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>CNAME</td>
<td>별칭 도메인</td>
</tr>
<tr>
<td>PTR</td>
<td>역방향 조회</td>
</tr>
</tbody></table>
<h2 id="raid-0-vs-raid-5">RAID 0 vs RAID 5</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>RAID 0</td>
<td>속도 향상, 스트라이핑</td>
</tr>
<tr>
<td>RAID 5</td>
<td>패리티 기반 장애 대응</td>
</tr>
</tbody></table>
<h2 id="ssh-vs-telnet">SSH vs Telnet</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>SSH</td>
<td>암호화 지원, 보안성 높음</td>
</tr>
<tr>
<td>Telnet</td>
<td>암호화 없음, 보안성 낮음</td>
</tr>
</tbody></table>
<h2 id="tftp-vs-ftp">TFTP vs FTP</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>FTP</td>
<td>TCP 기반, 파일 송수신 안정적</td>
</tr>
<tr>
<td>TFTP</td>
<td>UDP 기반, 단순하지만 손실 가능성 있음</td>
</tr>
</tbody></table>
<h2 id="public--private--hybrid-cloud">Public / Private / Hybrid Cloud</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>Public Cloud</td>
<td>외부 제공자가 관리</td>
</tr>
<tr>
<td>Private Cloud</td>
<td>조직 내부 전용</td>
</tr>
<tr>
<td>Hybrid Cloud</td>
<td>공용 + 사설 혼합</td>
</tr>
</tbody></table>
<h2 id="rip-vs-ospf-1">RIP vs OSPF</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>RIP</th>
<th>OSPF</th>
</tr>
</thead>
<tbody><tr>
<td>방식</td>
<td>거리 벡터</td>
<td>링크 상태</td>
</tr>
<tr>
<td>알고리즘</td>
<td>Bellman-Ford</td>
<td>Dijkstra / SPF</td>
</tr>
<tr>
<td>기준</td>
<td>Hop Count</td>
<td>Cost</td>
</tr>
<tr>
<td>규모</td>
<td>소규모</td>
<td>중대형</td>
</tr>
<tr>
<td>수렴 속도</td>
<td>느림</td>
<td>빠름</td>
</tr>
</tbody></table>
<hr>
<h1 id="21-암기용-핵심-포인트">21. 암기용 핵심 포인트</h1>
<ul>
<li>SSH 기본 포트: 22</li>
<li>HTTP 기본 포트: 80</li>
<li>HTTPS 기본 포트: 443</li>
<li>SNTP 포트: 123</li>
<li>FTP 데이터 포트: 20</li>
<li>DNS는 TCP와 UDP를 모두 사용</li>
<li>IPv4 루프백: 127.0.0.1</li>
<li>IPv6 생략 표기: <code>::</code></li>
<li>L2 스위치 기준: MAC 주소</li>
<li>L4 스위치 기준: TCP/UDP 포트</li>
<li>L7 스위치 기준: 응용 계층 정보</li>
<li>NAT: 사설 IP → 공인 IP 변환</li>
<li>DHCP: IP 자동 할당</li>
<li>PTR: 역방향 조회</li>
<li>CNAME: 별칭 도메인</li>
<li>SOA: Zone 파일의 첫 번째 레코드</li>
<li>RAID 0: 속도</li>
<li>RAID 5: 패리티</li>
<li>STP: 루프 방지</li>
<li>RIP: Bellman-Ford 사용</li>
<li>OSPF: Dijkstra / SPF 사용</li>
<li>RIP 기준: Hop Count</li>
<li>OSPF 기준: Cost</li>
<li>Sliding Window: TCP 흐름 제어</li>
<li>Stop and Wait / Go-Back-N / Selective Repeat: ARQ 방식</li>
<li><code>lastb</code>: 비인가 로그인 시도 확인</li>
<li><code>gdisk</code>: GPT 파티션</li>
<li><code>crontab -r</code>: crontab 삭제</li>
<li><code>inetmgr.exe</code>: IIS 관리자 실행</li>
<li><code>ipconfig /renew</code>: IP 재할당</li>
<li><code>netstat -r</code>: 라우팅 테이블 확인</li>
<li><code>pathping</code>: 경로 + 홉별 지연 정보 확인</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] NATURE-INSPIRED POPULATION-BASED EVOLUTION OF LARGE LANGUAGE MODELS]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-NATURE-INSPIRED-POPULATION-BASED-EVOLUTION-OF-LARGE-LANGUAGE-MODELS</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-NATURE-INSPIRED-POPULATION-BASED-EVOLUTION-OF-LARGE-LANGUAGE-MODELS</guid>
            <pubDate>Sat, 09 May 2026 08:40:59 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li><strong>기본 정보:</strong> 본 논문은 &quot;NATURE-INSPIRED POPULATION-BASED EVOLUTION OF LARGE LANGUAGE MODELS&quot;라는 제목으로 Yiqun Zhang 등(Northeastern University, Shanghai AI Lab)이 2025년 3월 4일에 발표한 연구입니다.</li>
<li><strong>핵심 목적 및 제안 방법:</strong> <strong>자연계의 집단 진화(Population-based Evolution) 원리</strong>에서 착안하여, <strong>다수의 전문가 LLM 가중치를 유전자처럼</strong> 취급해 그래디언트 업데이트 없이 교차, 변이, 계승 연산을 통해 새로운 태스크에 동적으로 적응시키는 GENOME 및 GENOME+ 프레임워크를 제안합니다.</li>
<li><strong>주요 성과 및 학술적 의의:</strong> 200개의 적은 샘플만으로 기존 최고 모델 대비 최대 54.8%의 정확도 향상을 기록했으며, 단일 24GB 메모리의 4090 GPU 환경에서도 원활하게 동작하여 대규모 모델 튜닝에 드는 막대한 비용을 절감하고 파운데이션 모델 개발의 민주화를 앞당겼습니다.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<ul>
<li><strong>연구 배경:</strong> LLM 생태계에는 <strong>특정 도메인에 미세 조정된 수많은 전문가 모델(Expert Models)</strong>이 존재합니다. 최근 연구들은 이러한 <strong>다양한 모델의 가중치를 병합(Merging)</strong>하여 새로운 역량을 이끌어내거나 미학습 태스크에 일반화하려는 시도를 이어가고 있습니다.</li>
<li><strong>기존 방법의 접근 방식:</strong> 기존 방식은 TIES, DARE와 같이 <strong>사전 정의된 규칙에 따라 정적으로</strong> 가중치를 병합하거나, LoRAHub, Model Swarms와 같이 <strong>적은 양의 검증 데이터를 활용해 동적인</strong> 융합 가중치를 탐색하는 방식으로 발전해 왔습니다.</li>
<li><strong>기존 방법의 한계:</strong> 기존의 병합 방식들은 궁극적으로 <strong>&#39;단일 모델&#39;을 만들어내는 데</strong> 집중합니다. 이는 추론 과정에서 다수 모델이 가진 <strong>앙상블 및 협력적 집단지성을 상실</strong>하게 만들며, 탐색 과정에서도 자연계가 보여주는 다각적인 진화 메커니즘(단순 유전자 교차를 넘은 경험의 계승 및 집단 의사결정)을 온전히 활용하지 못한다는 구조적 한계를 가집니다.</li>
<li><strong>문제 정의:</strong> 본 연구는 비용이 많이 드는 역전파(Backpropagation) 과정 없이, <strong>자연계의 집단 진화 원리</strong>를 빌려와 <strong>다수의 LLM 개체군(Population)이 협력적으로 파라미터를 최적화</strong>하고 <strong>완전히 새로운 태스크에 효과적으로 적응할 수 있는 프레임워크</strong>를 설계하는 것을 목표로 합니다.</li>
</ul>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/072ec53b-2303-490e-88bd-1aacadc8ff55/image.png" alt=""></p>
<p>본 논문은 LLM의 <strong>가중치(구체적으로 LoRA 파라미터)를 유전자(Gene)</strong>로, <strong>검증 세트에서의 성능을 적합도(Fitness)</strong>로 간주하여 최적화를 수행하는 <strong>GENOME</strong> 프레임워크와 이를 확장한 <strong>GENOME+</strong>를 제안합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/060fc3b2-2bdf-4de9-888e-a747c23748cf/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/50d57fd7-92d8-4aad-ad94-9678f1c0d7c2/image.png" alt=""></p>
<h2 id="학습-training--evolution-파이프라인">학습 (Training / Evolution) 파이프라인</h2>
<p>데이터가 네트워크에 주입되고 진화하는 과정은 크게 <strong>초기화, 교차, 변이, 계승, 선택</strong>의 단계로 이루어집니다. 이 과정은 모델 내부의 <strong>LoRA 가중치 공간에서 직접적인 행렬 연산</strong>을 통해 이루어지며, 손실 함수에 기반한 미분이 전혀 개입되지 않습니다.</p>
<ul>
<li><strong>초기화 (Initialization):</strong> 사전에 훈련된 $n$개의 전문가 모델 풀에서 무작위로 2개의 모델 $a, b$를 추출합니다. 이들의 LoRA 가중치 $w_a$와 $w_b$를 <strong>랜덤 스칼라 $t \sim U(0,1)$</strong>를 사용하여 선형 결합($w_i = t \cdot w_a + (1-t) \cdot w_b$)하는 방식으로, $N$개의 개체로 이루어진 초기 개체군(Population)을 구성합니다.</li>
<li><strong>교차 (Crossover):</strong> 우수한 특성을 결합하기 위해 개체군 내에서 적합도 비례 확률 $p_i = f_i / \sum_{k=1}^{N} f_k$에 따라 부모 쌍을 선택합니다. 선택된 <strong>부모 모델 $p1, p2$의 적합도를 기반으로 가중치 스칼라 $t = f_{p1} / (f_{p1} + f_{p2})$</strong>를 구한 뒤, <strong>새로운 자식 개체의 가중치를 $w_{child} = t \cdot w_{p1} + (1-t) \cdot w_{p2}$로 병</strong>합하여 다양성을 확보합니다.</li>
<li><strong>변이 (Mutation):</strong> 탐색 공간의 <strong>확장</strong>을 위해 설정된 확률(imr)에 따라 개체를 선택하고, <strong>선택된 개체의 개별 가중치에 확률(gmr)적으로 이진 마스크 $m_i$</strong>를 적용합니다. 마스킹된 가중치에는 <strong>가우시안 노이즈 $E_i \sim \mathcal{N}(0, \sigma^2)$</strong>가 더해져 파라미터가 섭동($w&#39;_i = w_i + m_i \cdot E_i$)되며, 이를 통해 국소 최적점(Local minima) 탈출을 유도합니다.</li>
<li><strong>계승 (Succession, GENOME+ 전용):</strong> 입자 군집 최적화(PSO)에서 영감을 받아 <strong>각 개체가 경험을 벡터 $e_i$ 형태로 누적</strong>합니다. 전체 최우수 모델($e_g$), 현재 세대 최우수 모델($e_c$), 전체 최악 모델($e_w$), 그리고 본인의 과거 경험($e_i$)을 조합하여 다음 수식으로 경험 벡터를 업데이트합니다.
$$
e_i \leftarrow \frac{1}{C} [\phi_e e_i + \phi_g(e_g - e_i) + \phi_c(e_c - e_i) - \phi_w(e_w - e_i)]
$$
업데이트된 경험은 학습률 $\lambda$를 곱해 현재 가중치에 직접 더해집니다 ($w_i \leftarrow w_i + \lambda e_i$). 이는 실패를 피하고 성공을 벤치마킹하는 엔지니어링 구조를 가중치 공간에 수학적으로 이식한 것입니다.</li>
<li><strong>선택 (Selection):</strong> 평가를 마친 개체군 중 상위 $\alpha N$ 비율의 <strong>엘리트 모델을 무조건 생존</strong>시키고, 나머지 공간은 전체 개체군을 대상으로 <strong>적합도 기반의 룰렛 휠 선택(Fitness-proportional sampling)</strong>을 적용하여 세대를 갱신합니다.</li>
</ul>
<h2 id="추론-inference-파이프라인">추론 (Inference) 파이프라인</h2>
<ul>
<li><strong>앙상블 (Ensemble, GENOME+ 전용):</strong> 단일 최적 모델만 사용하는 기존 방법과 달리, GENOME+는 테스트 시점에서 가장 적합도가 높은 <strong>상위 $k$개의 개체를 모두 활용</strong>합니다. 객관식의 경우 &#39;다수결(Majority Voting)&#39;을 채택하고, 생성형 태스크의 경우 텍스트 임베딩 후 BERTScore 기준 유사도가 가장 높은 결과를 도출하는 방식으로 집단지성 메커니즘을 완성합니다.</li>
</ul>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<ul>
<li><strong>실험 환경 및 비교 대상:</strong> 7개 능력 범주(수학, 코딩, 논리적 추론 등)에 걸친 12개 데이터셋이 사용되었습니다. Gemma-2-2b-it 기반으로 훈련된 10개의 전문가 모델을 초기 풀로 활용하였으며, Model Swarms, LoraHub, DARE TIES 등 7개의 융합 및 최적화 베이스라인과 200개의 적응(Adaptation) 샘플이라는 동일 조건 하에서 비교되었습니다.</li>
<li><strong>핵심 성능 결과:</strong> GENOME+는 모든 베이스라인을 압도했습니다. 평가 대상 중 &#39;최우수 단일 모델(Best Single)&#39; 대비 평균 24.06%, 직전 SOTA인 Model Swarms 대비 평균 10.75% 향상된 정확도를 기록했습니다.</li>
<li><strong>심층 분석 및 어블레이션:</strong></li>
<li><strong>추론(Reasoning) 능력 강화:</strong> DROP 데이터셋에서 54.80%, MGSM 데이터셋에서 19.31% 성능 향상을 보이며 수학 및 논리적 추론처럼 복잡성을 띠는 태스크에서 집단 진화 메커니즘이 크게 기능함을 입증했습니다.</li>
<li><strong>다중 태스크 및 제로샷 일반화:</strong> 모델 개체군이 두 개의 독립적인 태스크에 동시 적응해야 하는 상황이나, 추가 학습 샘플이 주어지지 않은 제로샷 전이(Zero-shot Transfer) 상황에서도 타 방법들과 달리 성능 저하 없이 안정적인 우위를 지켰습니다.</li>
<li><strong>어블레이션 스터디:</strong> 각 연산자를 제거하며 평가한 결과, 추론 단계에서의 <strong>앙상블(Ensemble) 연산 제거 시</strong> 성능 하락폭(-11.27%)이 가장 컸으며, <strong>올바른 선택(Selection) 연산과 계승(Succession) 연산</strong> 역시 높은 적합도를 유지하는 데 필수적임이 정량적으로 증명되었습니다.</li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<ul>
<li><strong>이론 및 성능적 한계:</strong><ul>
<li><strong>지식 집약적 태스크의 한계:</strong> 법률이나 역사 등 외부 지식을 묻는 태스크(Knowledge-based)에서는 추론 태스크 대비 성능 향상 폭이 상대적으로 미미했습니다. 파라미터 조합만으로는 모델이 학습하지 않은 팩트를 새롭게 창출할 수 없기 때문입니다.</li>
<li><strong>하이퍼파라미터 민감도:</strong> 교차율(Crossover Rate)과 개체 변이율(Individual Mutation Rate)이 극단적으로 높아지면 탐색 공간이 지나치게 커져 최적화(진화)에 소요되는 연산 시간이 급격하게 증가하는 트레이드오프가 존재합니다.</li>
</ul>
</li>
</ul>
<ul>
<li><strong>엔지니어링 고려 사항:</strong><ul>
<li>완전히 새로운 태스크에 적응하기 위해 여전히 최소 200개 규모의 정답 라벨이 포함된 검증(Validation) 데이터셋이 요구됩니다.</li>
<li>상위 $k$개 모델을 활용하는 앙상블 시스템 특성상 추론 단계에서 다중 모델을 VRAM에 로드하거나 병렬로 실행해야 하므로, 메모리 대역폭 관리 및 추론 지연 시간(Latency) 방어를 위한 시스템 엔지니어링이 필수적입니다.</li>
</ul>
</li>
</ul>
<ul>
<li><strong>연구의 시사점:</strong>
본 연구는 그래디언트 업데이트라는 병목 현상 없이, <strong>단순한 행렬 스칼라 연산(교차/변이/경험 계승)만으로 파라미터 공간을 최적화</strong>할 수 있음을 증명했습니다. 24GB VRAM을 지닌 소비자용 단일 GPU(RTX 4090)에서도 무리 없이 구현이 가능하다는 점은, 막대한 자본이 투입되는 파운데이션 모델 개발 패러다임 속에서 <strong>기학습된 모델 리소스를 재활용</strong>하고 커뮤니티 주도의 모델 발전을 가능케 하는 매우 실무적이고 가치 있는 접근입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] SPATIAL FORCING: IMPLICIT SPATIAL REPRESENTATION ALIGNMENT FOR VISION-LANGUAGE-ACTION
MODEL]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-SPATIAL-FORCING-IMPLICIT-SPATIAL-REPRESENTATION-ALIGNMENT-FOR-VISION-LANGUAGE-ACTIONMODEL</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-SPATIAL-FORCING-IMPLICIT-SPATIAL-REPRESENTATION-ALIGNMENT-FOR-VISION-LANGUAGE-ACTIONMODEL</guid>
            <pubDate>Sat, 02 May 2026 13:54:39 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li><strong>기본 정보:</strong> 본 논문은 &quot;Spatial Forcing: Implicit Spatial Representation Alignment for Vision-Language-Action Model&quot; (Fuhao Li 외, 2025년 10월)으로, 2D 시각 정보에 국한된 VLA 모델의 공간 인지 한계를 극복하기 위해 제안되었습니다.</li>
<li><strong>목적 및 방법:</strong> 명시적인 3D 센서 데이터(Depth/Point Cloud) 없이, 사전 학습된 3D 파운데이션 모델(VGGT)의 기하학적 표현을 VLA의 중간 시각 임베딩과 정렬(Alignment)함으로써 <strong>3D 공간 이해 능력을 암시적으로 강제(Forcing)</strong>합니다.</li>
<li><strong>성과 및 의의:</strong> 추론 시 추가 연산 부하 없이 기존 2D 및 3D VLA를 능가하는 SOTA 성능을 달성했으며, 학습 속도를 3.8배 가속하고 극단적인 데이터 효율성을 입증하여 실제 로봇 환경 적용의 범용성과 확장성을 크게 넓혔습니다.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<p>로봇 조작 분야에서는 언어 명령을 이해하고 물리적 제어를 수행하는 Vision-Language-Action (VLA) 모델이 핵심으로 자리 잡고 있습니다. 하지만 현재 대부분의 VLA 모델은 2D 시각 데이터로만 사전 학습된 Vision-Language Model (VLM)을 백본으로 사용하기 때문에, <strong>3D 물리 세계의 동적인 구조와 기하학적 관계를 정확히 추론하는 능력이 결여</strong>되어 있습니다. </p>
<p>기존 연구들은 이를 해결하기 위해 두 가지 주요 접근 방식을 취해왔습니다. 첫째는 뎁스 카메라나 라이다(Lidar)를 통해 <strong>깊이 맵이나 포인트 클라우드를 모델에 명시적으로 주입</strong>하는 방식입니다. 둘째는 <strong>2D 이미지 기반의 깊이 추정기(Depth estimator)</strong>를 활용해 3D 정보를 추정하는 방식입니다. 그러나 이러한 방식들은 치명적인 한계를 지닙니다. 센서 데이터는 <strong>노이즈가 많고 이질적</strong>이며, 기존의 거대한 로봇 데이터셋의 상당수는 <strong>3D 정보를 포함하고 있지 않아</strong> 확장성이 제한됩니다. 또한 깊이 추정기를 사용할 경우 추정기의 제한된 성능이 곧 전체 조작 성능의 병목이 됩니다. 실제로 논문에서 수행한 Depth Probing 실험에 따르면, 기존 VLA의 시각 임베딩은 유의미한 공간 구조를 전혀 형성하지 못하는 것으로 나타났습니다.<img src="https://velog.velcdn.com/images/jack_7711/post/9498290e-7f51-4944-893d-a9169ba51008/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/4eb3d4e4-586b-4e7f-b80f-30578525321a/image.png" alt=""></p>
<p>따라서 본 논문은 <strong>&quot;외부 3D 센서 데이터나 불안정한 깊이 추정기에 의존하지 않고, VLA 모델 내부의 시각적 표현이 암시적(implicitly)으로 3D 공간 인지 능력을 갖추도록 학습시킬 수 있는가?&quot;</strong>라는 핵심 문제를 정의하고 이를 해결하고자 합니다.</p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/b09d6e02-ee71-41e1-800f-38fdfab38355/image.png" alt=""></p>
<p>본 논문의 핵심 아이디어는 외부의 강력한 3D 파운데이션 모델이 추출한 <strong>정교한 3D 기하학적 표현을 정답지(Supervision signal)</strong>로 삼아, <strong>VLA 모델 내부의 중간 시각 토큰들</strong>이 이를 <strong>모방하도록 강제(Forcing)</strong>하는 것입니다. 이를 통해 VLA는 자기회귀(Auto-regressive) 생성 과정에서 <strong>공간 정보가 풍부하게 담긴 시각 토큰</strong>을 바탕으로 더욱 정밀한 행동(Action) 토큰을 생성할 수 있습니다.</p>
<h2 id="데이터-표현-및-전처리-방안">데이터 표현 및 전처리 방안</h2>
<p>로봇이 수집한 다중 시점(Multi-view) 2D 이미지 $I$는 학습 과정에서 두 갈래의 네트워크로 입력됩니다. 첫째, 입력 이미지 $I$는 <strong>사전 학습된 3D 파운데이션 모델</strong>인 VGGT($f^{3D}$)를 통과하여 픽셀 수준의 공간 표현인 $f^{3D}(I)$를 생성합니다. 이때 VLA의 자기회귀 특성상 공간적 위치 순서가 매우 중요하므로, 타겟 공간 표현에 위치 임베딩(Positional embedding) $E$를 더하여 최종 정답 신호 $f^{3D}<em>i(I) + E$를 구축합니다. 
둘째, 동일한 이미지가 <strong>VLA 내부의 시각 인코더(SigLIP, DINOv2 등)</strong>를 거쳐 $N$개의 시각 토큰 ${x^V_t}</em>{t=1}^N$으로 변환되며, 이 토큰들은 후속 트랜스포머 레이어를 통과하며 언어 토큰과 함께 연산됩니다.</p>
<h2 id="아키텍처의-세부-구조-및-핵심-수식">아키텍처의 세부 구조 및 핵심 수식</h2>
<p>VLA 모델의 $x^V_i$는 단순히 얕은 층이 아닌, <strong>충분히 깊은 특정 트랜스포머 중간 층(본 논문에서는 32개 층 중 24번째 층이 최적)에서 추출</strong>됩니다. 시각 특성이 <strong>모달리티에 종속되지 않는 수준으로 융합되기 직전의 층</strong>을 활용하는 것이 핵심 엔지니어링 디테일입니다. 추출된 시각 토큰 $x^V_i$는 타겟 공간 표현과 피처 차원(Feature dimension)을 맞추기 위해 배치 정규화(Batch Normalization, $\Gamma$)와 2-Layer MLP를 차례로 통과합니다. </p>
<p>이후 <strong>VLA의 임베딩과 VGGT의 3D 공간 표현 간의 코사인 유사도</strong>(Cosine Similarity, $\mathcal{S}$)를 최대화하는 정렬 손실(Alignment Loss)을 다음과 같이 계산합니다.
$$\mathcal{L}<em>{align} = - \frac{1}{N} \sum</em>{i=1}^N \mathcal{S}[\text{MLP} \cdot \Gamma(x^V_i), f^{3D}_i(I) + E]$$</p>
<p>최종 목적 함수는 로봇의 원래 과제인 행동 예측 손실($\mathcal{L}<em>{action}$)에 정렬 손실을 결합하여 최적화합니다.
$$\mathcal{L}</em>{SF} = \mathcal{L}<em>{action} + \alpha \mathcal{L}</em>{align}$$</p>
<h2 id="학습-및-추론-파이프라인의-차별성">학습 및 추론 파이프라인의 차별성</h2>
<ul>
<li><strong>학습(Training) 단계:</strong> VGGT 모델은 가중치가 동결된(Frozen) 상태로 작동하며, VLA 모델만이 기존의 $\mathcal{L}<em>{action}$과 $\mathcal{L}</em>{align}$을 동시에 최소화하도록 가중치를 업데이트합니다. 즉, 2D 행동 궤적 데이터를 학습하는 동시에 3D 공간 지식을 흡수합니다.</li>
<li><strong>추론(Inference) 단계:</strong> <strong>가장 강력한 기술적 차별성</strong>을 지니는 부분입니다. 학습이 종료된 후 실제 로봇에 모델을 배포할 때, VGGT 모델이나 피처 매핑을 위한 MLP 모듈 등은 완전히 제거됩니다. 오직 <strong>학습된 VLA 단일 모델만 동작</strong>하므로, 기존 2D VLA와 연산량 및 추론 속도가 100% 동일하며 명시적인 3D 센서 입력이 일절 필요하지 않습니다.</li>
</ul>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<ul>
<li><strong>평가 환경 및 세팅:</strong> LIBERO 벤치마크 (Spatial, Object, Goal, Long 시나리오) 및 다양한 환경 변수(조명, 레이아웃 등)가 포함된 RoboTwin (Real-to-Sim 벤치마크)에서 평가되었습니다. 실제 로봇 평가는 다관절 AgileX 플랫폼에서 수행되었습니다. 베이스라인으로는 OpenVLA-OFT, $\pi_0$와 같은 최신 2D VLA뿐만 아니라, Depth나 Point Cloud를 사용하는 명시적 3D VLA(GeoVLA, 3D-CAVLA) 모델들이 포함되었습니다.</li>
<li><strong>핵심 성능 결과:</strong> Spatial Forcing(SF)을 적용한 모델은 LIBERO 평균 성공률 98.5%를 기록하며 외부 3D 센서를 활용하는 모델들의 성능을 압도하는 SOTA를 달성했습니다. 특히 장기 의존성을 요구하는 Long-horizon 과제와 복잡성이 높은 RoboTwin의 Hard 세팅에서 압도적인 향상 폭을 보였습니다.</li>
<li><strong>학습 및 데이터 효율성:</strong> 중간 표현을 3D 구조로 직접 가이드함으로써 최적화 공간을 좁혀, 베이스라인 모델과 동일한 성능에 도달하는 데 걸리는 <strong>학습 반복 횟수(Iterations)를 3.8배 가속</strong>했습니다. 또한 전체 훈련 데이터의 5%만으로도 75.8%의 성공률을 달성하여, 동일 데이터량 대비 5.9배의 데이터 효율성을 보였습니다. </li>
<li><strong>해석 (t-SNE 시각화):</strong> SF 적용 후 VLA의 시각적 특징 분포는 타겟 3D 모델의 공간적 관계성(Distribution Shape)을 완벽히 모방하면서도, 군집의 중심(Cluster center)은 독립적으로 유지되었습니다. 이는 VLA가 고유의 시각적 식별 능력을 잃지 않으면서 물리적 차원의 기하학적 매니폴드(Manifold)만 정밀하게 정렬했음을 증명합니다.</li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<ul>
<li><strong>이론 및 엔지니어링적 한계:</strong> 본 방법론은 정답을 제공하는 특정 <strong>사전 학습 모델(VGGT)의 공간 이해 한계에 성능이 종속</strong>될 수밖에 없습니다. 또한, <strong>손실 가중치 $\alpha$를 지나치게 높게 설정하면 VLA의 본래 행동 토큰 생성 능력이 손상</strong>되는 표현 붕괴(Representational collapse) 현상이 발생할 위험이 있습니다. <strong>최적의 중간 레이어를 찾기 위해 네트워크 구조에 따른 수동적인 분석(예: 32개 층 중 24번째 층 선택)</strong>이 요구된다는 점도 한계로 작용합니다.</li>
<li><strong>실제 적용 시 과제:</strong> 학습 파이프라인에서 VGGT 모델을 메모리에 동시에 올려야 하므로, <strong>학습 단계에서의 VRAM 요구량 및 연산 오버헤드</strong>가 다소 증가합니다.</li>
<li><strong>시사점:</strong> 이 연구는 로봇 모델이 3D 세계를 이해하기 위해 <strong>반드시 물리적인 3D 센서가 필요한 것은 아니라</strong>는 패러다임 전환을 제시합니다. 막대한 양의 저품질 2D 비디오 데이터에 내재된 공간 정보를 발굴하여 VLA에 주입하는 이 방식은, 현재 심각한 병목을 겪고 있는 &#39;고품질 3D 로봇 데이터셋 부재&#39; 문제를 소프트웨어적으로 타개할 수 있는 강력한 대안적 훈련 프로토콜로 확장될 수 있습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] VLA-RFT: VISION-LANGUAGE-ACTION REINFORCEMENT FINE-TUNING WITH VERIFIED REWARDS IN
WORLD SIMULATORS]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-VLA-RFT-VISION-LANGUAGE-ACTION-REINFORCEMENT-FINE-TUNING-WITH-VERIFIED-REWARDS-INWORLD-SIMULATORS</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-VLA-RFT-VISION-LANGUAGE-ACTION-REINFORCEMENT-FINE-TUNING-WITH-VERIFIED-REWARDS-INWORLD-SIMULATORS</guid>
            <pubDate>Wed, 29 Apr 2026 10:50:59 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li><p>본 논문은 Vision-Language-Action(VLA) 모델의 <strong>모방 학습(Imitation Learning)이 지닌 한계</strong>를 극복하기 위해, 데이터 기반의 <strong>세계 모델(World Model)을 시뮬레이터로 활용</strong>하는 <strong>강화 미세조정(Reinforcement Fine-Tuning) 프레임워크</strong>인 VLA-RFT를 제안합니다.</p>
</li>
<li><p><strong>확장된 확률적 미분 방정식(SDE) 정책이 도출한 행동</strong>을 <strong>세계 모델에 주입</strong>하여 <strong>미래의 시각적 궤적(Visual Trajectory)을 생성</strong>하고, 이를 <strong>전문가 데이터와 비교</strong>하여 산출된 검증된 보상(Verified Reward)을 <strong>GRPO 알고리즘으로 최적화</strong>하는 구조를 갖습니다.</p>
</li>
<li><p><strong>단 400회의 최적화 단계만으로도</strong> 기존 지도 학습(SFT) 베이스라인 모델의 성능을 상회하며, <strong>환경 외란(Perturbation)에 대한 실패 복구 능력 및 강건성을 대폭 향상</strong>시켜 실용적이고 확장 가능한 VLA 모델 후학습 패러다임을 확립했습니다.</p>
</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<p>최근 Vision-Language-Action (VLA) 모델은 방대한 시각-언어 사전 학습 모델을 기반으로 구현되어 로봇 제어 및 의사 결정 분야에서 괄목할 만한 성과를 보여주었습니다. 현존하는 대부분의 VLA 모델은 방대한 시연 데이터를 바탕으로 한 <strong>모방 학습(Imitation Learning)에 의존</strong>하여 학습됩니다.</p>
<p>그러나 모방 학습 방식은 치명적인 구조적 한계를 내포하고 있습니다. 바로 <strong>분포 이동(Distribution shift) 하에서 발생하는 누적 오차(Compounding errors) 문제</strong>입니다. 전문가 시연에서 조금만 벗어난 상태에 진입하더라도, 모델은 <strong>낯선 상태에서 복구하는 방법을 학습하지 못했기 때문에</strong> 오류가 눈덩이처럼 불어나며 최종적으로 작업 실패로 이어집니다. </p>
<p>이를 해결하기 위해 <strong>탐색(Exploration)을 장려하는 강화학습(RL)</strong>을 도입하려는 시도가 이어지고 있습니다. 하지만 기존의 RL 파이프라인은 1) 실제 로봇을 통한 현실 세계 학습 시 <strong>천문학적인 비용과 심각한 안전 문제</strong>를 야기하며, 2) 시뮬레이터 기반 학습은 <strong>막대한 상호작용 횟</strong>수를 요구함과 동시에 <strong>Sim-to-Real(시뮬레이션-현실 간 간극) 문제</strong>에 취약하고, 3) 오프라인 RL은 <strong>환경과의 상호작용 없이</strong> 정적인 데이터에만 의존하므로 자신의 <strong>행동 결과로부터 학습할 수 없다</strong>는 문제에 직면해 있습니다.</p>
<p>본 논문은 이러한 딜레마를 해결하기 위해, 비싼 비용과 위험성 없이 실제 환경과 유사한 피드백을 제공할 수 있는 <strong>데이터 기반 세계 모델(Data-driven World Model)을 가상의 시뮬레이터로 활용하여 안전하고 효율적으로 VLA를 최적화하는 방법론</strong>을 정의하고 구축하는 것을 핵심 과제로 삼고 있습니다.</p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/e5f2fd15-c305-42e2-bf0c-5c7a9642c322/image.png" alt=""></p>
<p>VLA-RFT의 핵심 아이디어는 로봇의 상호작용 데이터로 <strong>사전 학습된 세계 모델을 통제 가능한 시뮬레이터로 전환</strong>하는 것입니다. <strong>정책 모델이 행동을 제안</strong>하면, <strong>세계 모델은 해당 행동이 초래할 미래의 시각적 관측값을 예측</strong>합니다. 생성된 합성 궤적을 <strong>전문가의 목표 궤적과 비교</strong>함으로써 궤적 수준의 조밀하고 직관적인 보상을 정책에 전달합니다. </p>
<h2 id="데이터-표현-및-전처리-방식">데이터 표현 및 전처리 방식</h2>
<p>본 모델은 다중 모달리티 데이터를 입력으로 받습니다. 초기 관측 이미지 $o_i$와 자연어 명령어 $l_i$는 사전 학습된 Vision-Language Model (VLM) 인코더인 $f_{\text{VLM}}$을 통과하여 잠재 표현(Latent representation) $z_i$로 변환됩니다. 로봇의 고유 상태(Proprioceptive state)인 $s_i$와 결합된 이 잠재 표현은 <strong>Flow-matching 기반의 행동 헤드 $\pi_{\theta}^{\text{fm}}$에 주입</strong>되어 연속적인 $T$ 차원의 행동 청크(Action chunk) 예측으로 이어집니다. 세계 모델의 경우 <strong>시각 정보는 이미지 토큰</strong>으로, <strong>연속적인 행동은 이산화된 행동 토큰</strong>으로 변환되어 트랜스포머 아키텍처 내에서 자기회귀적(Autoregressive)으로 처리됩니다.</p>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/3c811ac9-d3ab-4761-ba2f-1be1b32a3d2b/image.png" alt=""></p>
<h2 id="아키텍처-및-1단계-사전-학습-pre-training">아키텍처 및 1단계: 사전 학습 (Pre-training)</h2>
<p>안정적인 강화 미세조정을 위해, 네트워크는 최적화 이전 단계에서 <strong>오프라인 데이터를 통한 사전 학습</strong>을 거칩니다.</p>
<ol>
<li><p><strong>세계 모델 학습:</strong> VQGAN과 유사한 인코더와 12레이어 트랜스포머 백본으로 구성된 세계 모델은 이전 프레임과 행동이 주어졌을 때 다음 프레임을 예측하도록 훈련됩니다. 파라미터 $\phi$는 최대 우도 추정(MLE)을 통해 최적화됩니다.
$$
\mathcal{L}<em>{\text{MLE}}^{\text{WM}}(\phi) = -\mathbb{E} \left[ \log p_\phi(o</em>{i+1} | o_i, a_i) + \sum_{t=1}^{T-1} \log p_\phi(o_{i+t+1} | o_{i:i+t}, a_{i:i+t}) \right]$$
<img src="https://velog.velcdn.com/images/jack_7711/post/836d4b7c-cbe0-4270-b4a3-45ad86fd7449/image.png" alt=""></p>
</li>
<li><p><strong>VLA 정책 학습:</strong> 초기 행동의 안정성을 확보하기 위해 VLM 인코더와 Flow-matching 헤드는 전문가 시연 데이터를 바탕으로 연속적인 행동을 예측하도록 표준 MSE 손실(Flow-matching target)을 통해 지도 학습됩니다.
$$
\mathcal{L}<em>{\text{MSE}}^{\text{VLA}}(\theta) = \mathbb{E} \left[ | v_\theta(o_i, l_i, s_i, a</em>{i:i+T-1}^\tau) - u_\tau |^2_2 \right]$$
<img src="https://velog.velcdn.com/images/jack_7711/post/9962705f-b5a3-40a2-9d1d-e3df92442ced/image.png" alt=""></p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/3c811ac9-d3ab-4761-ba2f-1be1b32a3d2b/image.png" alt=""></p>
<h2 id="아키텍처-및-2단계-강화-미세조정-inference--training-pipeline">아키텍처 및 2단계: 강화 미세조정 (Inference &amp; Training Pipeline)</h2>
<p>본 논문의 기술적 차별성은 결정론적인 상미분 방정식(ODE)을 기반으로 하는 <strong>Flow-matching 정책을 확률론적 미분 방정식(SDE)으로 확장</strong>하여 탐색(Exploration)을 가능하게 한 점과, <strong>세계 모델과 GRPO를 결합한 파이프라인</strong>에 있습니다.</p>
<ol>
<li><p><strong>SDE-Policy 기반 탐색 및 추론:</strong> 강화학습을 위해서는 정책이 다양한 행동을 탐색하고 로그 우도(Log-likelihood)를 계산할 수 있어야 합니다. 이를 위해 VLA-RFT는 <strong>행동 헤드와 동일한 구조의 &#39;Sigma Net(파라미터 $\psi$)&#39;을 도입하여 노이즈 분산 벡터 $\sigma_\psi^k$를 출력</strong>합니다. 추론 시 Forward Euler 방법을 통해 $K=10$ 단계로 적분하며, 각 적분 단계 $k$에서 행동 청크는 다음과 같은 가우시안 분포에서 샘플링됩니다.
$$
a_{i:i+T-1}^{k\delta} \sim \mathcal{N}(\mu_k, \Sigma_k), \quad \text{where} ;; \Sigma_k = (\sigma_\psi^k)^2$$
이를 통해 <strong>전체 롤아웃에 대한 평균 로그 확률을 계산</strong>하고, 구정책(Old policy) 대비 비율(Policy ratio) $r$을 산출합니다.</p>
</li>
<li><p><strong>세계 모델 상호작용 및 검증된 보상(Verified Reward) 산출:</strong> <strong>SDE-Policy가 제안한 행동 청크</strong>가 세계 모델에 입력되면, 세계 모델은 합성 <strong>시각적 궤적 $\hat{o}_{i+1:i+T+1}$</strong>을 생성합니다. 이 합성 궤적을 오프라인 <strong>데이터셋의 Ground-Truth 이미지 $o_{i+1:i+T+1}$와 비교</strong>하여, <strong>픽셀 레벨(L1) 차이</strong>와 <strong>지각적 유사도(LPIPS)</strong>의 음수 가중합으로 명확한 보상 $R$을 도출합니다.
$$ 
R = -\sum_{t=0}^{T-1} \left[ \lambda_1 L_1(\hat{o}<em>{i+t+1}, o</em>{i+t+1}) + \lambda_{lp} \text{LPIPS}(\hat{o}<em>{i+t+1}, o</em>{i+t+1}) \right]$$</p>
</li>
<li><p><strong>GRPO를 이용한 정책 업데이트:</strong> 도출된 보상 $R$을 <strong>동일 그룹(동일 시작 상태) 내 롤아웃들의 평균 보상($\bar{R}_{\text{group}}$)과 빼서</strong> Advantage를 구합니다. 이후 행동 공간의 <strong>과도한 변화를 막기 위한 클리핑(Clipping) 항</strong>, <strong>모델 안정성을 위한 보조 MSE 손실</strong>, <strong>탐색을 유도하는 정책 엔트로피 $\mathcal{H}$</strong>를 결합하여 GRPO 목적 함수로 $\theta$와 $\psi$를 최종 업데이트합니다.
$$
\mathcal{L}<em>{\text{GRPO}}^{\text{VLA}}(\theta, \psi) = -\mathbb{E}\left[ \text{clip}(r, 1-\epsilon, 1+\epsilon) \text{Adv} \right] + \lambda</em>{\text{mse}}\mathcal{L}<em>{\text{MSE}}^{\text{VLA}}(\theta) - \alpha\mathcal{H}(\pi</em>{\theta,\psi})$$</p>
</li>
</ol>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<p>실험은 <strong>조작 및 환경의 일반화를 평가</strong>하는 <strong>LIBERO 벤치마크 데이터셋</strong>에서 진행되었습니다. 기반이 되는 비교 대상(Baseline)은 강력한 지도 학습(SFT) 미세조정 방식이 적용된 VLA-Adapter의 경량 버전입니다. 세계 모델은 138M 파라미터의 LLaMA 아키텍처를 차용하여 효율성을 극대화했습니다.<img src="https://velog.velcdn.com/images/jack_7711/post/4e493ca5-fb20-4459-a60f-ad496e35c139/image.png" alt=""></p>
<h2 id="핵심-성능-standard-settings">핵심 성능 (Standard Settings)</h2>
<p>베이스라인 모델이 150,000스텝의 광범위한 지도 학습을 거쳐 평균 86.6%의 성공률(SR)을 기록한 반면, VLA-RFT는 사전 학습 모델에 단 400회(0.4K)의 RFT 반복만 추가했음에도 성공률을 91.1%로 끌어올렸습니다. 이는 대규모 상호작용을 요구하는 기존 시뮬레이터 기반 RL이나 방대한 연산을 요구하는 지도 학습에 비해 압도적인 샘플 효율성과 성능 개선을 의미합니다.</p>
<h2 id="강건성-확보-및-어블레이션-perturbation-settings">강건성 확보 및 어블레이션 (Perturbation Settings)</h2>
<p>이 방법론이 가장 두각을 나타낸 부분은 분포 이동 상황에서의 성능(Robustness)입니다. 로봇의 초기 높이나 물체의 위치를 의도적으로 변형시킨 외란(Perturbation) 환경에서, 베이스라인 정책은 성능이 극심하게 하락했습니다(예: 복합 주요 외란에서 34.0%). 반면, VLA-RFT는 <strong>향상된 행동 탐색 범위(Action distribution coverage)</strong> 덕분에 예기치 못한 환경 변화 속에서도 오류를 자체 복구(Failure recovery)하며 높은 작업 안정성을 유지했습니다(+3.0% ~ +6.7%의 성능 방어율).
또한, 보상 체계에 대한 어블레이션 결과, 단순히 정책과 데이터셋의 행동 값(Action)의 거리 차이만을 보상으로 삼았을 때는 성능 향상이 미미했습니다(+1.1%). 그러나 세계 모델이 생성한 동일한 가상 공간 내에서 궤적 전체의 픽셀/지각적 유사도를 평가한 VLA-RFT 보상 방식(+4.5%)이 가장 높은 일반화 성능을 견인했음이 증명되었습니다.</p>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<h2 id="한계-및-엔지니어링적-과제">한계 및 엔지니어링적 과제</h2>
<p>본 논문은 명확한 한계점 역시 공유하고 있습니다. </p>
<ol>
<li><strong>전문가 의존성:</strong> 현재 보상 함수는 세계 모델이 예측한 궤적이 기존 전문가 시연 데이터(Ground-Truth)와 얼마나 유사한지에 전적으로 의존합니다. 따라서 정책이 전문가 데이터를 능가하는 <strong>새로운 최적의 제어 전략을 스스로 발굴하는 데에는 제약</strong>이 따릅니다.</li>
<li><strong>세계 모델 용량 병목:</strong> <strong>세계 모델 자체의 표현 용량(Representational capacity) 한계</strong>가 최종 성능에 직접적인 영향을 미칩니다. 장기적인 일관성을 유지하고 더 복잡한 물리 동역학을 모델링하기 위해 대규모 데이터와 파라미터를 활용한 스케일 업이 필요합니다.</li>
<li><strong>계획(Planning) 구조의 부재:</strong> <strong>세계 모델을 미래 상태의 보상 검증 수단으로만 한정</strong>하였으며, 추론 단계에서 경로를 탐색하는 장기 계획(Long-horizon reasoning/planning) 모듈로 직접 통합하지는 못했습니다.</li>
</ol>
<h2 id="시사점">시사점</h2>
<p>그럼에도 불구하고 VLA-RFT는 실제 로봇에서의 <strong>무모한 탐색 연산이나, 물리적 오류가 만연한 시뮬레이션 환경에 얽매이지 않고도</strong> 안전하고 실용적으로 VLA 모델을 고도화할 수 있음을 입증했습니다. 특히 세계 모델을 &#39;데이터 기반 평가자(Simulator)&#39;로 도입함으로써 단 400회의 미세조정만으로 SFT의 누적 오차 한계를 타파하고 강건성을 확보한 점은, 향후 스케일러블(Scalable)한 로봇 기반 멀티모달 파운데이션 모델의 후학습 방향성에 지대한 학술적 이정표를 제시합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] CodeGraphVLP: Code-as-Planner Meets Semantic-Graph State for
Non-Markovian Vision-Language-Action Models]]></title>
            <link>https://velog.io/@jack_7711/CodeGraphVLP-Code-as-Planner-Meets-Semantic-Graph-State-forNon-Markovian-Vision-Language-Action-Models</link>
            <guid>https://velog.io/@jack_7711/CodeGraphVLP-Code-as-Planner-Meets-Semantic-Graph-State-forNon-Markovian-Vision-Language-Action-Models</guid>
            <pubDate>Mon, 27 Apr 2026 06:13:19 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li><p>본 논문은 <strong>비마르코프(Non-Markovian) 환경의 장기(Long-horizon) 로봇 조작 한계</strong>를 극복하기 위해, 지속적인 <strong>&#39;의미론적 그래프(Semantic-Graph)&#39; 상태</strong>와 <strong>&#39;코드 기반 계획기(Code-as-Planner)&#39;</strong>를 결합한 <strong>CodeGraphVLP 프레임워크</strong>를 제안합니다.</p>
</li>
<li><p>매 스텝 VLM을 호출하는 대신 <strong>초기 1회 생성된 실행 가능한 코드로 작업 진척도를 효율적으로 추적</strong>하며, <strong>서브태스크와 관련된 객체만</strong> 남긴 <strong>&#39;클러터 제거 시각-언어 프롬프트&#39;를 생성</strong>하여 <strong>저수준 VLA(Vision-Language-Action) 모델의 시각적 그라운딩 성능을 극대화</strong>했습니다.</p>
</li>
<li><p>실제 로봇 실험 결과, 기존의 메모리 증강 VLA나 VLM-in-the-loop 방식보다 <strong>계획 지연 시간을 약 1/10 수준으로 단축</strong>하면서도, <strong>복잡하고 방해물(Clutter)이 많은 환경</strong>에서의 작업 성공률을 비약적으로 향상시켰습니다.</p>
</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<h2 id="연구의-배경">연구의 배경</h2>
<p>최근 대규모 로봇 데이터를 바탕으로 사전 학습된 VLM을 행동 예측에 적용하는 VLA 모델이 로봇 제어의 범용성을 크게 확장하고 있습니다. 그러나 대부분의 VLA 모델은 <strong>&#39;현재 시점의 관찰값만으로 다음 행동을 결정할 수 있다&#39;는 마르코프(Markovian) 가정</strong>에 기반한 단기(Short-horizon) 정책으로 학습 및 배포됩니다.</p>
<h2 id="기존-방법의-접근-방식과-한계">기존 방법의 접근 방식과 한계</h2>
<p>실제 환경의 장기 조작 작업은 <strong>과거의 관찰이 현재의 결정에 필수적인 비마르코프적 특성</strong>을 지닙니다. 이를 해결하기 위해 두 가지 주요 접근법이 존재했습니다.</p>
<ol>
<li><strong>메모리 증강 VLA (Memory-augmented VLA):</strong> 과거 프레임, 메모리 토큰, 또는 과거 경험 검색을 활용합니다. 하지만 메모리 용량과 연산 효율성 간의 상충 관계(Trade-off)가 발생하며, <strong>긴 시계열에서 희소한 핵심 증거를 놓치기 쉽습니다</strong>.</li>
<li><strong>계층적 VLM-VLA (Hierarchical VLM-VLA):</strong> 거대 VLM을 고수준 계획기로 두고 <strong>서브태스크를 VLA에 전달</strong>합니다. 하지만 매 스텝 VLM을 호출하여 막대한 추론 지연(Latency)이 발생하며, <strong>언어만으로 전달되는 지시</strong>는 방해물이 많은(Cluttered) 환경에서 VLA의 잘못된 시각적 그라운딩을 유발합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/7f4aeed3-b0b1-4fd2-9b02-cf217e7028c8/image.png" alt=""></li>
</ol>
<h2 id="핵심-문제-정의">핵심 문제 정의</h2>
<p>본 논문은 &quot;어떻게 하면 <strong>막대한 추론 지연 없이</strong> 과거의 관찰 정보를 포함한 <strong>&#39;작업 상태&#39;를 명시적으로 유지</strong>하면서, 동시에 복잡한 환경에서도 저수준 제어기(VLA)가 <strong>방해물에 흔들리지 않고</strong> 정확한 시각-언어적 행동 추론을 수행할 수 있을 것인가?&quot;를 핵심 문제로 정의하고 이를 해결하고자 합니다.</p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/3b6a62a0-b4af-4e97-a4cf-389209898b71/image.png" alt=""></p>
<h2 id="전체-핵심-아이디어">전체 핵심 아이디어</h2>
<p>CodeGraphVLP는 부분적 관찰 가능성을 극복하기 위해 (1) 물체와 그 관계를 기록하는 <strong>의미론적 그래프(Semantic-graph) 상태</strong>를 지속적으로 유지하고, (2) LLM이 초기 1회 작성한 <strong>코드 기반 계획기(Code-as-Planner)</strong>를 통해 그래프를 조회하여 작업 진척도를 파악하며, (3) <strong>계획기가 반환한 관련 물체들만</strong> 남긴 <strong>방해물 제거 시각-언어 프롬프트(Clutter-free Visual-Language Prompting)</strong>를 VLA에 주입하여 정확한 동작을 유도합니다.</p>
<h2 id="입력-데이터의-표현-및-전처리-그래프-초기화-및-업데이트">입력 데이터의 표현 및 전처리 (그래프 초기화 및 업데이트)</h2>
<p>입력 데이터인 다중 시점 RGB 이미지 $o_t$는 그래프 상태 $G_t = (V_t, E_t)$로 변환됩니다.</p>
<ol>
<li><strong>분할 및 관련성 필터링:</strong> YOLOE를 통해 인스턴스 마스크를 추출하고, Set-of-Mark 기법을 적용해 VLM에 질의하여 작업과 관련된 객체만 필터링합니다.</li>
<li><strong>다중 시점 연관 (Multi-view Association):</strong> 시점 간 객체 매칭을 위해 먼저 CLIP 특징 벡터의 코사인 유사도를 <strong>임계값 $\tau_{vis}$로 평가</strong>합니다. 남은 객체들은 <strong>기하학적 거리를 기반으로 매칭</strong>합니다. <strong>마스크 $m^v$의 무게중심 $c(m^v) \in \mathbb{R}^2$와 앵커 $a^v$의 거리</strong>를 다음 수식으로 계산합니다.
$$
d(m^v, a^v) = | c(m^v) - c(a^v) |<em>2$$
이후 각 시점의 스케일 차이를 보정하기 위해 최대 앵커 거리로 정규화한 **서명(Signature) $\tilde{d}^v(m)$을 임계값 $\tau</em>{geo}$와 비교**하여 최종 매칭을 수행합니다.</li>
<li><strong>온라인 업데이트:</strong> 추론 중에는 <strong>Cutie 트래커를 사용</strong>하여 $G_{t-1}$의 마스크를 현재 관찰값 $o_t$로 갱신하며, 놓친 객체는 YOLOE로 재탐지하여 갱신합니다.</li>
</ol>
<h2 id="모델-세부-구조-및-알고리즘-프름">모델 세부 구조 및 알고리즘 프름</h2>
<h3 id="1-code-as-planner의-구조-및-작동">1. Code-as-Planner의 구조 및 작동</h3>
<p>작업 초기, LLM은 <strong>전체 지시어 $l$과 초기 그래프 $G_0$</strong>를 바탕으로 <strong>파이썬 함수 형태의 정책 $\mathcal{P}$를 1회 합성</strong>합니다. 이 코드는 <code>graph.task_memory</code>라는 리스트를 통해 <strong>완료된 서브태스크를 캐싱</strong>하여 중복 실행을 방지합니다. </p>
<p>추론 시 매 스텝 계획기를 호출하면 다음과 같은 <strong>서브태스크 지시어</strong>와 <strong>관련 객체 집합</strong>을 반환합니다.
$$
l_t^{sub}, O_t^{rel} = \mathcal{P}(G_t)$$</p>
<h3 id="2-방해물-제거-프롬프팅-clutter-free-visual-language-prompting">2. 방해물 제거 프롬프팅 (Clutter-Free Visual-Language Prompting)</h3>
<p>단순 언어 지시어 $l_t^{sub}$만 VLA에 넘기면 방해물에 취약합니다. 따라서 뷰 $v$에서 객체 $i$의 이진 분할 마스크 $m_{i,t}^v$를 활용하여, 서브태스크와 관련된 객체만 남기는 <strong>유지 마스크(Retention Mask) $M_t^v$</strong>를 생성합니다.
$$
M_t^v = \max_{i \in O_t^{rel}} m_{i,t}^v$$
원본 이미지 $I_t^v$에 이를 원소별 곱(Element-wise multiplication)하여 <strong>방해물이 제거된 이미지 $\tilde{I}_t^v$</strong>를 만듭니다.
$$
\tilde{I}_t^v = I_t^v \odot M_t^v$$</p>
<h3 id="3-학습-및-추론-파이프라인">3. 학습 및 추론 파이프라인</h3>
<ul>
<li><strong>학습(Training):</strong> 원본 텔레오퍼레이션(Teleoperation) 궤적을 제안된 파이프라인을 통해 전처리하여 <strong>방해물이 제거된 관찰 $\tilde{o}$, 로봇 상태 $s$, 행동 궤적 $\tau$, 서브태스크 지시어 $l^{sub}$ 쌍</strong>으로 구성된 데이터셋 $\mathcal{D}$를 구축합니다. VLA(본 논문에서는 $\pi_0$ 활용)는 최대 우도 추정(MLE)을 통해 다음 수식으로 미세조정(Fine-tuning)됩니다.
$$
\max_\theta \mathbb{E}_{(\tilde{o},s,\tau,l^{sub}) \sim \mathcal{D}} [\log \pi_\theta(\tau | \tilde{o}, s, l^{sub})]$$</li>
<li><strong>추론(Inference):</strong> 새로운 관찰 $o_t$가 들어오면 $\rightarrow$ 의미론적 그래프 $G_t$ 업데이트 $\rightarrow$ $\mathcal{P}(G_t)$ 실행하여 $l_t^{sub}, O_t^{rel}$ 획득 $\rightarrow$ 방해물 제거 이미지 $\tilde{o}_t$ 생성 $\rightarrow$ VLA가 행동 $\tau_t$를 예측하여 실행하는 사이클을 반복합니다. 이는 <strong>VLM 호출 없이 가벼운 코드 실행만</strong>으로 이루어집니다.</li>
</ul>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<h2 id="실험-세팅-및-비교-대상">실험 세팅 및 비교 대상</h2>
<p>UR10e 다관절 로봇과 평행 그리퍼, 2개의 카메라(전역 및 손목 뷰)를 활용하여 실제 환경의 3가지 비마르코프/클러터 환경 과제(Pick-and-Place Twice, Place-and-Stack, Swap Cups)를 설계했습니다.
비교 대상(Baseline)으로는 최신 VLA 모델인 $\pi_0$, $\pi_0$ FAST, $\pi_{0.5}$, Gr00T N1.5와, 과거 4프레임을 추가로 입력받는 다중 프레임(Multi-frame) Gr00T N1.5를 사용했습니다.</p>
<h2 id="핵심-성능-및-해석">핵심 성능 및 해석</h2>
<ul>
<li><strong>정량적 성공률:</strong> CodeGraphVLP는 3개 과제 평균 <strong>81.7%</strong>의 성공률을 기록하여, 가장 성능이 좋았던 Multi-frame Gr00T N1.5(56.7%)를 큰 격차로 압도했습니다. </li>
<li><strong>계획 효율성 (Latency):</strong> 매 스텝 VLM을 호출하는 기존 방식(VLM-in-the-loop)이 스텝 당 3.142초가 걸린 반면, Code-as-Planner는 <strong>0.328초</strong>로 지연 시간을 획기적으로 낮춰 폐루프(Closed-loop) 제어의 실효성을 증명했습니다.</li>
<li><strong>어블레이션 스터디 (방해물 제거 효과):</strong> Swap Cups 과제에서 서브태스크 관련 객체만 남기는 시각적 마스킹(Clutter-free visual)을 제거하자 성공률이 85%에서 40%로 급락했습니다. 이는 복잡한 씬에서 언어만으로는 VLA의 시각적 그라운딩을 이끌기 부족하며, 본 논문의 시각-언어 프롬프팅이 핵심적인 역할을 함을 증명합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/9427fd5f-dfae-480e-92cf-d8068522961b/image.png" alt=""></li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<h2 id="한계점-및-실제-적용-시-제약">한계점 및 실제 적용 시 제약</h2>
<ul>
<li><strong>파운데이션 모델 의존성:</strong> 시스템 초기화 단계에서 <strong>VLM과 LLM의 성능에 전적으로 의존</strong>합니다. VLM이 객체의 속성이나 관계를 잘못 추론(환각 현상)하거나 분할 모델(YOLOE)이 실패할 경우, 잘못된 그래프와 코드 계획기가 생성되어 복구가 불가능해집니다.</li>
<li><strong>개방형 세계(Open-world)의 제약:</strong> 현재는 <strong>사전에 지정된 뷰와 정적 관계 유추 규칙(in, on, near)에 의존</strong>하고 있어, 형태가 고정되지 않은 유연한 물체나 매우 복잡한 기하학적 결합에는 적용하기 어렵습니다.</li>
</ul>
<h2 id="연구의-의의-및-향후-방향">연구의 의의 및 향후 방향</h2>
<p>본 연구는 대규모 VLM의 강력한 인지 및 추론 능력을 <strong>초기 1회의 &#39;코드 생성&#39;과 &#39;그래프 초기화&#39;</strong>로 응축하고, 실제 제어는 <strong>가벼운 VLA와 코드 스크립트로 분리</strong>하여 실행 속도와 시각적 견고함을 동시에 달성했다는 점에서 엔지니어링적 가치가 매우 높습니다.</p>
<p>향후 연구로는 자<strong>동화된 검증(Verification)</strong>을 통해 LLM이 생성한 파이썬 <strong>플래너의 오류를 스스로 수정하는 메커니즘</strong>을 추가하거나, 동적인 3D 환경을 포괄할 수 있는 개방형 의미론적 그래프 생성 모듈을 개발하는 방향으로 확장될 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] Long-Horizon Manipulation via
Trace-Conditioned VLA Planning]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-CodeGraphVLP-Code-as-Planner-Meets-Semantic-Graph-State-forNon-Markovian-Vision-Language-Action-Models</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-CodeGraphVLP-Code-as-Planner-Meets-Semantic-Graph-State-forNon-Markovian-Vision-Language-Action-Models</guid>
            <pubDate>Mon, 27 Apr 2026 05:27:53 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li><strong>목적 및 제안 방법:</strong> 긴 시계열(Long-horizon) 로봇 조작의 복잡성을 해결하기 위해 <strong>고수준의 작업 관리자(VLM)와 저수준의 실행기(VLA)를 분리</strong>하고, <strong>2D 시각적 궤적(Trace)을 매개체로 연결</strong>하는 LoHo-Manip 프레임워크를 제안함.</li>
<li><strong>기술적 차별성:</strong> 매 스텝마다 <strong>&#39;남은 계획(Remaining Plan)&#39;</strong>과 <strong>&#39;시각적 궤적&#39;</strong>을 예측하는 후퇴 지평(Receding-horizon) 제어 방식을 도입하여, 별도의 복구 로직 없이도 <strong>실행 오류로부터 자가 수정 및 재계획</strong>이 가능한 폐루프(Closed-loop) 시스템을 구축함.</li>
<li><strong>성과 및 의의:</strong> 시뮬레이션 및 실제 로봇 실험에서 기존 단일 구조 VLA 대비 월등한 <strong>장기 작업 성공률</strong>을 보였으며, 특히 학습되지 않은 물체와 환경에 대한 강력한 <strong>제로샷 일반화 성능</strong>을 입증함.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<h2 id="기존-연구의-흐름과-한계">기존 연구의 흐름과 한계</h2>
<p>최근 VLA(Vision-Language-Action) 모델의 발전으로 단기적인(Short-horizon) 로봇 기술(집기, 놓기 등)은 비약적으로 향상되었습니다. 그러나 여러 단계가 복합적으로 얽힌 <strong>장기적 작업(예: &quot;주전자에 물 채우기&quot;)에서</strong>는 다음과 같은 치명적인 한계가 존재합니다.</p>
<ol>
<li><strong>오류의 누적(Compounding Errors):</strong> 단일 모델이 전체 과정을 추론할 경우, <strong>중간 단계의 미세한 실행 오류</strong>가 다음 단계의 입력 왜곡으로 이어져 전체 작업이 실패하는 취약성을 보입니다.</li>
<li><strong>모듈성 결여:</strong> 계획(Planning)과 실행(Execution)이 <strong>단일 네트워크에 강하게 결합</strong>되어 있어, 새로운 로봇 하드웨어나 환경에 맞춰 모델을 업그레이드하거나 교체하기가 매우 어렵습니다.</li>
<li><strong>분포 외 데이터(OOD)에 대한 취약성:</strong> <strong>학습 데이터에 존재하지 않는</strong> 복합 지시어나 생소한 물체 배치에 대해 추론 능력이 급격히 저하됩니다.</li>
</ol>
<h2 id="핵심-문제-정의">핵심 문제 정의</h2>
<p>본 논문은 <strong>&quot;고수준의 인지적 판단(무엇을 할 것인가)&quot;</strong>과 <strong>&quot;저수준의 물리적 제어(어떻게 움직일 것인가)&quot;</strong>를 어떻게 효과적으로 <strong>분리</strong>하면서도 긴밀하게 <strong>연결</strong>할 것인가를 핵심 문제로 정의합니다. 특히, 실행 중 발생하는 <strong>예외 상황</strong>을 인간의 개입 없이 스스로 인지하고 수정할 수 있는 견고한 <strong>작업 관리 메커니즘</strong>의 부재를 해결하고자 합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/3abc24a8-9176-4239-90ab-794c648b65a8/image.png" alt=""></p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/cfff5703-85a3-4d03-9389-8137dba06174/image.png" alt=""></p>
<h2 id="전체-아이디어-task-manager와-executor의-분리">전체 아이디어: Task Manager와 Executor의 분리</h2>
<p>LoHo-Manip은 <strong>복잡한 지시어를 원자 단위의 서브태스크(Sub-task)로 분해</strong>하는 <strong>Task Manager(VLM)</strong>와, 전달받은 시각적 가이드를 따라 로봇을 움직이는 <strong>Executor(VLA)</strong>로 구성된 계층적 구조를 가집니다.</p>
<h2 id="데이터-표현-및-전처리-방식">데이터 표현 및 전처리 방식</h2>
<p>모델에 주입되는 데이터는 단순한 RGB 이미지를 넘어 고도의 정제 과정을 거칩니다.</p>
<ul>
<li><strong>서브태스크 분해:</strong> 비디오 데이터를 <strong>VLM</strong>을 통해 분석하여 <strong>상호작용 이벤트(Grasp, Place 등) 단위</strong>로 세그멘테이션하고 자연어 레이블을 생성합니다.</li>
<li><strong>2D Visual Trace 추출:</strong> <strong>로봇의 엔드 이펙터(End-effector) 위치</strong>를 픽셀 좌표 $p_t \in \mathbb{R}^2$로 추출하여, 이를 <strong>정규화된 2D 웨이포인트(Waypoint) 시퀀스</strong>로 변환합니다. 이 궤적은 이후 <strong>이미지 위에 렌더링</strong>되어 실행기에 <strong>&quot;시각적 프롬프트&quot;로 주입</strong>됩니다.<img src="https://velog.velcdn.com/images/jack_7711/post/de7b53ee-9a53-4622-afc6-deb3d0559dc8/image.png" alt=""></li>
</ul>
<h2 id="모델-세부-구조-및-핵심-수식">모델 세부 구조 및 핵심 수식</h2>
<p>Task Manager는 현재 관찰값 $o_t$와 이전까지의 수행 이력 $C_{t-1}$을 입력받아 <strong>진행 상황 인지 계획(Progress-aware plan)</strong>을 생성합니다.</p>
<ol>
<li><p><strong>텍스트 기반 메모리:</strong> 전체 작업 시퀀스를 <strong>수행 완료된 부분($C_t^\star$)</strong>과 <strong>남은 부분($R_t^\star$)</strong>으로 명시적으로 분리하여 관리합니다.
$$
C_t^\star = [\bar{s}^{(1)}, \dots, \bar{s}^{(k(t)-1)}], \quad R_t^\star = [\bar{s}^{(k(t))}, \dots, \bar{s}^{(K)}]$$
여기서 <strong>$k(t)$는 현재 시점에서 수행해야 할 서브태스크의 인덱스</strong>입니다.</p>
</li>
<li><p><strong>Visual Trace (시각적 궤적):</strong> 단순한 목표 지점이 아니라, 미래의 엔드 이펙터 <strong>이동 경로를 시퀀스 데이터로</strong> 예측합니다.
$$
\tau_t^\star = {p_t, p_{t+1}, \dots, p_{t_K^e}}$$
이 궤적 $\tau_t$는 <strong>이미지 상에 선 형태</strong>로 렌더링되어 <strong>VLA의 공간적 어텐션(Spatial Attention)</strong>을 가이드합니다.</p>
</li>
</ol>
<h2 id="학습-및-추론-파이프라인">학습 및 추론 파이프라인</h2>
<ul>
<li><strong>학습 단계:</strong> </li>
</ul>
<ol>
<li><strong>Manager 학습:</strong> 대규모 VLM(예: Qwen3-VL)을 기반으로, 현재 프레임에서 <strong>남은 서브태스크 텍스트</strong>와 <strong>2D 궤적</strong>을 예측하도록 파인튜닝합니다.<ol start="2">
<li><strong>Executor 학습:</strong> 기존 VLA 모델(예: $\pi_0$)이 <strong>이미지 위에 렌더링된 Trace를 조건부 입력</strong>으로 받아 <strong>해당 경로를 추적하며 액션을 생성</strong>하도록 학습시킵니다.</li>
</ol>
</li>
</ol>
<ul>
<li><strong>추론 단계 (Closed-loop):</strong> 매 스텝 혹은 일정 주기마다 Manager가 &quot;현재 상황에서 남은 최적의 경로&quot;를 다시 계산(Receding Horizon)합니다. 만약 로봇이 물체를 놓치는 오류가 발생하면, 다음 스텝의 관찰값 <strong>$o_{t+1}$에 실패 상태가 반영</strong>되므로 Manager는 <strong>자동으로 동일한 서브태스크를 다시 계획하거나 복구 경로를 생성</strong>합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/e4d00e01-0851-45b5-8c80-75b6dcb7cebc/image.png" alt=""></li>
</ul>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<h2 id="평가-환경-및-비교-대상">평가 환경 및 비교 대상</h2>
<ul>
<li><strong>데이터셋:</strong> Bridge dataset(Open X-Embodiment) 기반의 실제 로봇 데이터와 LIBERO, VLABench 등 시뮬레이션 벤치마크를 사용했습니다.</li>
<li><strong>Baseline:</strong> $\pi_0$, OpenVLA, GR00T 등 최신 단일 구조 VLA 모델들과 성능을 비교했습니다.</li>
</ul>
<h2 id="주요-성과-및-해석">주요 성과 및 해석</h2>
<ol>
<li><strong>장기 작업 성공률:</strong> VLABench의 Semantic Instruction 트랙에서 기존 모델들이 17~20%의 성공률을 보인 반면, LoHo-Manip은 <strong>39%</strong>로 두 배 이상의 성능 향상을 기록했습니다.</li>
<li><strong>오류 복구 능력:</strong> 로봇이 엉뚱한 물체를 집었을 때, &quot;물체를 내려놓고 다시 목표 물체로 이동하라&quot;는 복구 서브태스크와 궤적을 스스로 생성하는 능력이 확인되었습니다.</li>
<li><strong>제로샷 일반화 (OOD):</strong> 학습 시 보지 못한 물체가 포함된 실제 로봇 환경에서도 Task Manager가 일반적인 VLM의 추론 능력을 발휘하여 정확한 2D 궤적을 생성함으로써, 실행기가 성공적으로 작업을 완수했습니다.<img src="https://velog.velcdn.com/images/jack_7711/post/2e22bd53-2670-4f85-8fdc-f3d033908813/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/84a01ab9-dcb5-4a2f-ac3d-4f77a1f27236/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/e847a839-ed28-49b7-9159-b631d0e3de29/image.png" alt=""><img src="https://velog.velcdn.com/images/jack_7711/post/f8c8626e-a620-424a-92c7-810f56e524ab/image.png" alt=""></li>
</ol>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<h2 id="기술적-한계-및-과제">기술적 한계 및 과제</h2>
<ul>
<li><strong>2D 표현의 제약:</strong> 현재의 시각적 궤적은 <strong>2D 픽셀 좌표에 기반</strong>하고 있어, 3D 공간에서의 정밀한 깊이 제어나 복잡한 접촉이 필요한(Contact-rich) 동작에서는 정보 손실이 발생할 수 있습니다.</li>
<li><strong>Manager 의존성:</strong> 고수준 계획의 품질이 Task Manager인 <strong>VLM의 성능에 전적으로 의존</strong>하므로, 인지 모델의 환각(Hallucination) 현상이 발생할 경우 잘못된 가이드를 제공할 위험이 있습니다.</li>
</ul>
<h2 id="연구의-의의와-향후-방향">연구의 의의와 향후 방향</h2>
<p>LoHo-Manip은 거대 언어 모델의 <strong>&#39;추론 능력&#39;</strong>을 로봇의 <strong>&#39;동작 제어&#39;</strong>에 직접적으로 <strong>연결</strong>하는 가장 <strong>효율적인 인터페이스로 &#39;Visual Trace&#39;</strong>를 제시했다는 점에서 큰 학술적 가치가 있습니다. 이는 향후 <strong>로봇 시스템이 독립적인 제어 모듈을 유지</strong>하면서도, 최신 VLM의 성능 향상을 즉각적으로 흡수할 수 있는 <strong>확장 가능한 아키텍처</strong>를 제시한 것으로 평가됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] PersonaVLM: Long-Term Personalized Multimodal LLMs]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-PersonaVLM-Long-Term-Personalized-Multimodal-LLMs</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-PersonaVLM-Long-Term-Personalized-Multimodal-LLMs</guid>
            <pubDate>Fri, 24 Apr 2026 13:33:35 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li>본 논문은 멀티모달 대형 언어 모델(MLLM)이 사용자의 진화하는 선호도와 성격을 장기적으로 학습하고 유지하지 못하는 문제를 해결하기 위해 <strong>PersonaVLM</strong> 프레임워크를 제안함.</li>
<li>기억(Memory), 추론(Reasoning), 응답 정렬(Response Alignment)의 세 가지 핵심 기능을 통합한 <strong>개인화 메모리 아키텍처</strong>와 <strong>성격 진화 메커니즘(PEM)</strong>을 도입함.</li>
<li>장기 개인화 벤치마크인 <strong>Persona-MME</strong>를 구축하여 검증한 결과, 기존 베이스라인 대비 22.4%의 성능 향상을 기록하며 GPT-4o를 상회하는 개인화 성능을 입증함.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<p>현재의 멀티모달 대형 언어 모델(MLLM)은 수백만 명의 일상 비서 역할을 수행하고 있으나, <strong>개별 사용자의 독특한 특성과 시간에 따라 변하는 선호도에 맞춰 응답하는 능력은 여전히 제한적</strong>입니다.</p>
<p>기존의 개인화 연구들은 주로 <strong>입력 증강(Input Augmentation)</strong>이나 <strong>정적인 출력 정렬(Output Alignment)</strong>에 집중해 왔습니다. 이러한 접근 방식은 다음과 같은 두 가지 핵심적인 한계를 가집니다.</p>
<ul>
<li><strong>정적 선호도의 한계:</strong> 사용자의 선호도는 상호작용 과정에서 변화(예: 특정 음료에 대한 선호 변화)하지만, 기존 모델은 <strong>과거의 고정된 기억에 의존</strong>하여 부적절한 제안을 하는 경우가 많습니다.</li>
<li><strong>성격 정렬의 부재:</strong> 사용자의 성격(내향성, 신경증 등)은 여러 대화에 걸쳐 미묘하게 드러나지만, 기존 기술은 이를 <strong>동적으로 파악하고 응답 톤을 조절하는 메커니즘이 부족</strong>합니다.</li>
</ul>
<p>따라서 본 연구는 MLLM이 사용자의 의도를 정확히 추론하고, 행동을 개인의 가치관과 정렬하며, 멀티모달 정보를 지속적으로 기억하도록 하는 <strong>장기 개인화 에이전트 프레임워크</strong> 구축을 핵심 과제로 정의합니다.</p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p>본 논문은 일반 목적의 MLLM을 개인화 비서로 전환하기 위한 두 단계의 협업 프로세스(Response &amp; Update)와 고도화된 메모리 구조를 제안합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/422a23be-4a44-4188-99c0-7777d251daf8/image.png" alt=""></p>
<h2 id="개인화-메모리-아키텍처-personalized-memory-architecture">개인화 메모리 아키텍처 (Personalized Memory Architecture)</h2>
<p>사용자의 정보는 크게 두 가지 카테고리로 저장 및 관리됩니다.</p>
<ol>
<li><strong>사용자 성격 프로필 (P):</strong> 사용자의 성격을 <strong>Big Five(OCEAN)</strong> 모델에 따라 5차원 벡터로 정량화하여 관리합니다.</li>
<li><strong>멀티타입 메모리 데이터베이스 (M):</strong><ul>
<li><strong>Core Memory:</strong> 사용자의 이름, 나이, 직업 등 핵심 정체성 정보.</li>
<li><strong>Semantic Memory:</strong> 사실 관계, 개념, 멀티모달 시각적 개념(Visual Concepts) 등 추상적 지식.</li>
<li><strong>Episodic Memory:</strong> 대화 세션을 주제별로 구분한 타임스탬프 기반의 사건 기록.</li>
<li><strong>Procedural Memory:</strong> 사용자의 장기 목표, 반복적인 습관 및 루틴.</li>
</ul>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/62c5c0c5-9f39-455c-bf28-2f5a0120a246/image.png" alt=""></p>
<h2 id="응답-단계-response-stage와-추론-메커니즘">응답 단계 (Response Stage)와 추론 메커니즘</h2>
<p>사용자의 쿼리가 입력되면 PersonaVLM은 다음과 같은 에이전트 기반 추론 루프를 실행합니다.</p>
<ul>
<li><strong>다단계 추론:</strong> 모델은 현재 쿼리와 대화 문맥을 분석하여 메모리 검색이 필요한지 스스로 결정합니다.</li>
<li><strong>에이전트 검색:</strong> 부족한 정보가 있다면 검색 키워드와 시간 범위를 포함한 검색 쿼리를 생성합니다.</li>
<li><strong>정렬된 생성:</strong> 검색된 메모리를 통합하여 사용자의 Big Five 성격 점수에 최적화된 톤과 내용으로 최종 응답 $R_m$을 생성합니다.</li>
</ul>
<h2 id="업데이트-단계-update-stage와-pem">업데이트 단계 (Update Stage)와 PEM</h2>
<p>상호작용이 완료된 후, 모델은 백그라운드에서 메모리를 갱신합니다.</p>
<ul>
<li><strong>성격 진화 메커니즘 (PEM):</strong> 사용자의 최신 발화에서 성격 점수 $p&#39;<em>m$을 추론하고, 모멘텀 기반의 지수 이동 평균(EMA)을 사용하여 장기 프로필을 업데이트합니다.
  $$
  p_m \leftarrow \lambda \cdot p</em>{m-1} + (1 - λ) \cdot p&#39;_m$$
  여기서 $\lambda$는 대화 초기에는 낮게 설정하여 적응력을 높이고, 대화가 진행될수록 코사인 스케줄링을 통해 높여 안정성을 확보합니다.</li>
<li><strong>지식 추출:</strong> 상호작용에서 핵심 정보를 추출하여 4가지 메모리 타입에 반영하며, 시각적 개념의 경우 <strong>Grounding DINO</strong>를 활용하여 이미지 크롭과 텍스트를 매핑하여 저장합니다.</li>
</ul>
<h2 id="학습-파이프라인-training-pipeline">학습 파이프라인 (Training Pipeline)</h2>
<ul>
<li><strong>Stage 1 (SFT):</strong> 500개의 고유한 페르소나를 바탕으로 합성된 3만 건 이상의 멀티모달 상호작용 데이터를 사용하여 메모리 관리 및 추론 능력을 학습시킵니다.</li>
<li><strong>Stage 2 (RL):</strong> <strong>Group Relative Policy Optimization (GRPO)</strong>를 적용하여 모델의 다단계 추론 성능을 강화합니다. 정확도, 논리적 일관성, 형식 준수 여부를 보상(Reward) 함수로 설정하여 최적화합니다.<img src="https://velog.velcdn.com/images/jack_7711/post/f0cf9bce-07cf-4068-a5bb-a07b3ff046db/image.png" alt=""></li>
</ul>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<h2 id="평가-환경-및-데이터셋">평가 환경 및 데이터셋</h2>
<ul>
<li><strong>Persona-MME:</strong> 본 연구에서 새로 구축한 벤치마크로, 7가지 측면(기억, 의도, 선호, 행동, 관계, 성장, 정렬)과 14개의 미세 태스크를 포함하는 2,000개 이상의 케이스로 구성됩니다.</li>
<li><strong>PERSONAMEM:</strong> 기존의 동적 사용자 프로파일링 벤치마크를 활용하여 장기 문맥(128k)에서의 성능을 측정했습니다.</li>
</ul>
<h2 id="주요-성능-지표">주요 성능 지표</h2>
<ul>
<li><strong>성능 향상:</strong> 128k 문맥 조건에서 PersonaVLM은 베이스라인 모델 대비 Persona-MME에서 <strong>22.4%</strong>, PERSONAMEM에서 <strong>9.8%</strong>의 정확도 향상을 보였습니다.</li>
<li><strong>타 모델 비교:</strong> GPT-4o와 비교했을 때 Persona-MME에서 5.2% 더 높은 점수를 기록했으며, 특히 사용자의 행동 양식 파악 및 성장 모델링(Skill-level tailoring) 측면에서 압도적인 우위를 보였습니다.</li>
<li><strong>정성적 평가:</strong> Gemini-2.5-Pro를 판독관(Judge)으로 사용한 개방형 응답 평가에서 PersonaVLM은 사실 정확성과 성격 정렬도 모두에서 타 모델 대비 높은 승률(Win-rate)을 기록했습니다.<img src="https://velog.velcdn.com/images/jack_7711/post/ffdebb89-9d63-426a-b5fb-9aea2f97decf/image.png" alt=""></li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<h2 id="한계점">한계점</h2>
<ul>
<li><strong>연산 및 지연 시간:</strong> 다단계 추론 및 메모리 검색 과정을 포함하므로, 베이스라인 모델 대비 응답 지연 시간(Latency)이 약 21% 증가하는 엔지니어링적 비용이 발생합니다.</li>
<li><strong>모달리티 확장성:</strong> 현재는 텍스트와 이미지 중심의 개인화에 집중되어 있으며, 비디오나 오디오 신호를 통한 실시간 인물 추적 및 감정 분석까지는 확장되지 않았습니다.</li>
<li><strong>기억의 통합:</strong> 타임라인 기반 검색에는 능숙하지만, 서로 다른 시점에 발생한 유사한 에피소드를 논리적으로 병합하거나 모순을 해결하는 고도화된 메모리 정제 기능이 보완되어야 합니다.</li>
</ul>
<h2 id="시사점-및-학술적-의의">시사점 및 학술적 의의</h2>
<p>PersonaVLM은 MLLM을 단순한 도구에서 사용자와 함께 성장하는 <strong>&#39;장기 동반자&#39;</strong>로 진화시켰다는 점에서 의의가 큽니다. 특히 상호작용을 통해 성격 벡터를 동적으로 보정하는 PEM과 로컬 환경에서도 작동 가능한 메모리 아키텍처는 데이터 프라이버시 보호와 고도의 개인화가 동시에 요구되는 의료, 교육, 추천 시스템 분야에 중요한 기술적 토대를 제공합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] Near-Future Policy Optimization]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-Near-Future-Policy-Optimization</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-Near-Future-Policy-Optimization</guid>
            <pubDate>Fri, 24 Apr 2026 13:14:52 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li>본 논문은 강화학습(RLVR) 기반의 언어 모델 튜닝에서, 현재 정책보다 조금 앞선 <strong>&#39;가까운 미래(Near-Future)&#39; 체크포인트가 생성한 정답 궤적을 활용</strong>하여 학습을 최적화하는 NPO(Near-Future Policy Optimization)를 제안한다.</li>
<li>외부 교사 모델이나 과거 모델을 활용하는 기존 방식들의 한계인 궤적 품질(Quality)과 기울기 분산(Variance) 간의 상충 관계를 <strong>수학적 유효 학습 신호 지표인 $S=Q/V$를 통해 분석</strong>하고, 최적의 탐색-활용 균형을 달성하는 파이프라인을 구축했다.</li>
<li>Qwen3-VL-8B 모델에 적용한 결과, <strong>초기 학습의 수렴 속도를 2.1배 가속화함</strong>과 동시에 후반부 성능 정체를 돌파하여 멀티모달 수학 추론 벤치마크에서 <strong>최고 성능을 기록</strong>하는 학술적 의의를 보여주었다.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<p>강화학습을 통한 언어 모델의 사후 학습, 특히 <strong>명확한 검증 보상을 활용하는 RLVR(Reinforcement Learning with Verifiable Rewards)</strong>은 모델의 추론 능력을 극대화하는 핵심 기법으로 자리 잡았다. 그러나 <strong>순수 온폴리시(On-policy) 기반</strong>의 RLVR, 예를 들어 GRPO 등은 구조적으로 두 가지 한계에 직면한다. 첫째, <strong>학습 초기에는</strong> 모델이 정답 궤적을 스스로 생성할 확률이 낮아 <strong>보상 신호가 희소(Sparse)</strong>하다. 둘째, <strong>학습 후반부에는</strong> 궤적 분포가 좁아져 새로운 해결책을 탐색하지 못하고 특<strong>정 성능에서 정체(Plateau)되는 현상</strong>이 발생한다.</p>
<p>이를 <strong>극복하기 위해 오프폴리시(Off-policy) 궤적을 혼합</strong>하는 방법들이 연구되었다. 하지만 기존 방법론들은 심각한 딜레마를 안고 있다. 외부 교사 모델(External Teacher)이나 완전히 학습이 끝난 모델(Far-future)의 <strong>궤적은 품질($Q$)은 높지만</strong>, <strong>현재 모델과의 파라미터 및 분포 차이</strong>가 커서 <strong>막대한 기울기 분산($V$)을 유발해 학습을 불안정</strong>하게 만든다. 반대로 <strong>과거 학습 궤적(Experience Replay)을 재사용</strong>하는 경우, <strong>분산은 적으나 품질 자체가 낮아</strong> 모델에게 새로운 지식을 제공하지 못한다. </p>
<p>결과적으로, 이 논문은 <strong>유효 학습 신호(Effective Learning Signal)를 $S = Q/V$</strong> 로 정의하고, 너무 멀지도 가깝지도 않아 $S$ 값을 극대화할 수 있는 &#39;이상적인 궤적 공급원&#39;을 설계해야 한다는 핵심 문제를 정의 및 해결하고자 한다.</p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/09b7c238-b36e-40fb-96d1-71e407e4950e/image.png" alt=""></p>
<p>NPO의 핵심 아이디어는 외부의 강력한 모델에 의존하는 대신, 자기 <strong>자신의 최적화 경로상에 있는 &#39;가까운 미래($\Delta$ 스텝 이후)&#39;의 체크포인트를 활용</strong>하는 것이다. <strong>가까운 미래의 모델은 현재보다 더 많이 학습되었으므로 품질($Q$)이 높으면서도, 파라미터 이동 거리가 짧아 기울기 분산($V$)이 적다</strong>는 구조적 이점을 취한다.</p>
<h2 id="입력-데이터-전처리-및-궤적-획득-data-representation">입력 데이터 전처리 및 궤적 획득 (Data Representation)</h2>
<p>NPO는 훈련 과정을 잠시 멈추고 <strong>$\Delta$ 스텝만큼 탐색 학습(Scout run)을 진행하여 미래 정책 $\pi^{(t+\Delta)}$를 확보</strong>한다. 이후 $\pi^{(t+\Delta)}$를 이용해 오프라인 환경에서 훈련 프롬프트 $x$들에 대해 응답을 롤아웃(Rollout)하고 검증기를 통과시킨다. 이때 <strong>검증을 통과한 &#39;정답 궤적&#39; 중 하나를 가이던스 궤적 $o&#39;_x$로 선택</strong>하여 캐싱(Caching)한다. 미래 정책조차 정답을 내지 못한 프롬프트는 제외된다. 이렇게 생성된 <strong>캐시 데이터는 NPO가 적용되는 세그먼트 구간 동안 재사용</strong>되어 추가적인 추론 비용을 방지한다.</p>
<h2 id="학습-및-추론-파이프라인-구조-pipeline-engineering">학습 및 추론 파이프라인 구조 (Pipeline Engineering)</h2>
<p>학습(Training) 단계에서 NPO는 <strong>원본 RLVR(GRPO)의 구조를 최대한 보존하면서 데이터를 주입</strong>한다.</p>
<ol>
<li>스텝 $t$에서 현재 정책 $\pi^{(t)}$는 $n$개의 궤적 $o_i$를 온폴리시로 샘플링한다.</li>
<li>해당 그룹의 정답률 $\hat{p}(x) = \frac{1}{n} \sum_{i=1}^n r(x, o_i)$를 계산한다.</li>
<li>$\hat{p}(x) \le \tau_{gate}$ 인 경우, 즉 현재 모델이 해당 프롬프트를 어려워하는 경우에만 개입한다. <strong>생성된 $n$개의 궤적 중 마지막 슬롯($n$번째)을 캐싱해둔 미래 궤적 $o&#39;_x$로 강제 교체</strong>한다.
$$G_{NPO}(x) = {o_1, \dots, o_{n-1}, \tilde{o}_n}$$</li>
<li>교체된 그룹 $G_{NPO}(x)$에 대해 평균과 표준편차를 구하여 Advantage $A_i$를 산출하고, GRPO와 동일한 클리핑(Clipping) 목적 함수 $L_{NPO}(\theta)$를 통해 정책을 업데이트한다.</li>
</ol>
<p>추론(Inference) 단계에서는 어떠한 아키텍처나 파이프라인의 수정도 요구되지 않는다. 학습이 완료된 후 표준적인 자동 회귀(Auto-regressive) 디코딩을 그대로 수행한다.</p>
<h2 id="autonpo-적응형-동적-스케줄링">AutoNPO: 적응형 동적 스케줄링</h2>
<p>수동으로 특정 시점에 개입하는 것을 넘어, 논문은 AutoNPO라는 확장 모델을 제안한다. AutoNPO는 <strong>온라인 훈련 중 보상의 정체나 엔트로피의 감소와 같은 훈련 신호를 지속적으로 모니터링</strong>한다. 개입이 필요하다고 판단되면, 경험적 추정을 통해 유효 학습 신호 <strong>$S(\Delta)$를 극대화하는 최적의 거리 $\Delta^*$를 계산하고 자동으로 미래 궤적을 주입</strong>한다.</p>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<p>실험은 다중 모달 능력을 갖춘 Qwen3-VL-8B-Instruct 모델을 기반으로 진행되었으며, RL 알고리즘으로는 GRPO가 사용되었다. 성능 평가는 고난도 수학 추론 벤치마크인 MMMU-Pro, MathVista, MathVision, WeMath를 대상으로 하였다.</p>
<ul>
<li><strong>핵심 성능 결과:</strong> 기존 순수 GRPO 베이스라인이 평균 57.88%의 성능을 기록한 반면, NPO를 적용했을 때 평균 62.84%로 대폭 상승했다. 자동화된 AutoNPO를 적용한 경우 63.15%의 최고 성능을 달성하여, 외부 교사 모델이나 과거 경험 리플레이를 사용한 기존 최상위 방법론들을 모두 능가했다.</li>
<li><strong>초기 가속과 후반부 돌파:</strong> 학습 동인(Dynamics) 측면에서 두 가지 명확한 성과가 관찰되었다. 초기 개입(Early Intervention)을 적용했을 때는 순수 GRPO 대비 훈련 수렴 속도가 약 2.1배 가속화되었다. 후반부 개입(Late Intervention)을 적용했을 때는 기존 온폴리시 모델이 도달한 후 더 이상 성장하지 못하는 한계점(Plateau)을 부수고 성능 천장을 높이는 데 성공했다.</li>
<li><strong>어블레이션 해석:</strong> 거리 $\Delta$에 따른 $Q(\Delta)$와 $V(\Delta)$의 변화를 분석한 결과, $\Delta$가 너무 크면 분산이 지수적으로 폭발하고, 너무 작으면 품질 이득이 적음을 실증했다. 특정 중간 구간(예: $\Delta \approx 20 \sim 70$)에서 $S(\Delta)$가 명확한 극댓값을 형성하여 최적의 탐색-활용 균형이 이루어짐을 입증했다.</li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<h2 id="한계점-및-제약-조건">한계점 및 제약 조건</h2>
<p>본 방법론은 미래의 체크포인트를 확보하기 위해 $\Delta$ 스텝만큼의 사전 훈련(Scout run)을 선행해야 하므로, 이 과정에서 <strong>일시적인 컴퓨팅 오버헤드</strong>가 발생한다는 구조적 한계가 있다. 또한, NPO의 메커니즘은 정답의 유무를 명확히 판별할 수 있는 검증 가능 보상(Verifiable Reward)이 존재하는 환경(수학, 코딩 등)을 전제로 설계되었기 때문에, 개방형 대화나 창의적 글쓰기와 같은 모호한 태스크에 직접 적용하기 위해서는 <strong>추가적인 보상 모델(Reward Model) 설계</strong>가 요구된다.</p>
<h2 id="향후-연구-방향-및-시사점">향후 연구 방향 및 시사점</h2>
<p>그럼에도 불구하고 NPO는 강화학습 과정에서 발생하는 탐색 부족 문제를 &#39;미래의 자아(Near-future self)&#39;를 통해 해결했다는 점에서 매우 혁신적이다. 오프폴리시 데이터 활용의 본질적인 문제인 품질-분산 트레이드오프(Quality-Variance Trade-off)를 수학적으로 정립하고, 외부 데이터 의존성 없이 자체 학습 사이클 내에서 모델 스스로의 한계를 극복하는 방법을 제시했다. 이는 향후 LLM 자기 주도적 정렬(Self-alignment) 및 진화형 훈련 파이프라인 설계에 핵심적인 이론 및 엔지니어링적 토대를 제공할 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[논문 리뷰] DiPO: Disentangled Perplexity Policy Optimization for
Fine-grained Exploration-Exploitation Trade-Off]]></title>
            <link>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-DiPO-Disentangled-Perplexity-Policy-Optimization-forFine-grained-Exploration-Exploitation-Trade-Off</link>
            <guid>https://velog.io/@jack_7711/%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0-DiPO-Disentangled-Perplexity-Policy-Optimization-forFine-grained-Exploration-Exploitation-Trade-Off</guid>
            <pubDate>Fri, 24 Apr 2026 12:38:19 GMT</pubDate>
            <description><![CDATA[<h1 id="0-3줄-요약">0. 3줄 요약</h1>
<ul>
<li>본 논문은 대형 언어 모델(LLM)의 강화학습 과정에서 발생하는 <strong>극단적 샘플(전체 정답 또는 전체 오답)의 기울기 소실 및 비효율적 탐색-활용 딜레마를 해결</strong>하기 위한 DiPO(Disentangled Perplexity Policy Optimization)를 제안한다.</li>
<li>퍼플렉서티(PPL)와 정답 확률의 통계적 상관관계를 분석하여 탐색/활용 공간을 분리(PSD)하고, 기존 검증 보상의 분포를 해치지 않으면서 <strong>특정 샘플의 보상만을 미세 조정하는 양방향 보상 재할당(BRR) 메커니즘</strong>을 도입했다.</li>
<li>수학적 추론 및 함수 호출 태스크에서 기존 GRPO 및 DAPO 대비 일관되고 우수한 성능 향상을 달성하였으며, 특히 학습 후반부의 탐색 정체 현상을 방지하여 모델의 추론 능력을 극대화하는 학술적 의의를 지닌다.</li>
</ul>
<hr>
<h1 id="1-배경-및-문제-정의">1. 배경 및 문제 정의</h1>
<p>강화학습 기반의 LLM 튜닝, <strong>특히 검증 가능한 보상을 사용하는 RLVR(Reinforcement Learning with Verifiable Rewards)</strong>은 모델의 추론 능력을 비약적으로 향상시켰다. 이 중 <strong>GRPO(Group Relative Policy Optimization) 패러다임은 가치 네트워크(Value Network) 없이 그룹 내 상대적 이점을 계산</strong>하여 효율성을 극대화했다. </p>
<p>그러나 기존 GRPO 기반 방법론은 탐색-활용 상충 관계(Exploration-Exploitation Trade-Off)에서 두 가지 치명적인 한계를 지닌다.
첫째, <strong>극단적 샘플의 기울기 소실 문제</strong>다. 학습이 진행됨에 따라 다수의 샘플 그룹이 모두 오답인 Hard 그룹(보상 0)이거나 모두 정답인 Easy 그룹(보상 1)으로 양극화된다. 이 경우 <strong>그룹 내 보상 편차가 0</strong>이 되므로 <strong>Advantage 산출값 역시 0</strong>이 되어, 더 나은 방향으로의 학습(탐색 및 활용)을 이끌어낼 <strong>Gradient가 소실</strong>된다.
둘째, <strong>비효율적인 탐색과 활용</strong>이다. 샘플의 생성 확률(Perplexity, PPL) 분포를 보면, PPL이 높은(탐색적) 정답 샘플이나 PPL이 낮은(활용적) 오답 샘플이 <strong>혼재</strong>한다. DACE나 CDE 등 기존 연구들은 PPL을 직접적인 보상으로 사용하여 이를 해결하려 했으나, 이는 <strong>검증 보상의 본래 분포를 크게 훼손</strong>하여 추가적인 학습 불안정성을 초래하는 문제가 발생한다.</p>
<p>본 논문은 기존 보상 체계의 안정성을 유지하면서도, PPL을 기준으로 <strong>&#39;어떤 오답 샘플을 더 탐색하게 할 것인지&#39;</strong>, <strong>&#39;어떤 정답 샘플의 엔트로피를 낮춰 활용하게 할 것인지&#39;</strong>를 세밀하게 제어하는 것을 핵심 문제로 정의한다.<img src="https://velog.velcdn.com/images/jack_7711/post/5db64252-d904-4eec-8645-66d7d1b18142/image.png" alt=""></p>
<hr>
<h1 id="2-제안-방법-method">2. 제안 방법 (Method)</h1>
<p><img src="https://velog.velcdn.com/images/jack_7711/post/bf83c9e6-26e4-42f5-bce8-55099a40404a/image.png" alt=""></p>
<p>DiPO의 핵심 아이디어는 <strong>생성된 응답들의 PPL 공간을 통계적으로 분리</strong>하여 탐색과 활용이 필요한 대상을 <strong>명확히 식별</strong>하고, <strong>원래의 학습 안정성을 훼손하지 않는 선</strong>에서 <strong>핀포인트로 보상을 재할당</strong>하는 것이다. </p>
<h2 id="입력-데이터-표현-및-전처리-ppl-queue">입력 데이터 표현 및 전처리 (PPL Queue)</h2>
<p>모델은 주어진 쿼리 $q$에 대해 $G$개의 응답 $o_i$를 샘플링한다. 각 응답에 대해 환경으로부터 얻은 이진 검증 보상 $R(o_i, a)$와 모델의 내부 토큰 생성 확률 기반의 PPL 값 $p_i$를 산출한다. 이 <strong>데이터 쌍 $(p_i, r_i)$는 PPL Queue에 지속적으로 캐싱</strong>되어, 온라인 학습 과정에서 PPL과 정답률 간의 동적 통계 확률을 추정하는 데 사용된다.</p>
<h2 id="perplexity-space-disentangling-psd">Perplexity Space Disentangling (PSD)</h2>
<p>동적 통계를 바탕으로 전체 샘플 공간을 탐색 공간(Exploration Space, $P &gt; \tau$)과 활용 공간(Exploitation Space, $P &lt; \tau$)으로 분리하는 <strong>최적의 임계값 $\tau^*$를 찾는다</strong>.
단순히 특정 임계값을 고정하는 것이 아니라, 다음의 엔지니어링 파이프라인을 거친다.</p>
<ol>
<li><strong>Advantage Judgment:</strong> 특정 임계값 $\tau$를 기준으로, 탐색 공간에서의 &#39;오답 우위&#39;와 활용 공간에서의 &#39;정답 우위&#39;가 <strong>통계적으로 유의미한지</strong> 판단한다. 노이즈를 제어하기 위해 95% 신뢰구간(Wald approximation)의 하한값과 상한값을 교차 검증하여, <strong>두 공간이 확실하게 분리될 수 있는 후보군 $C$를 필터링</strong>한다.</li>
<li><strong>Minimizing Classification Errors:</strong> 필터링된 후보군 중, PPL만으로 정답/오답을 분류했을 때 오차가 가장 적은 최적의 임계값 $\tau^<em>$를 다음 수식을 통해 계산한다.
$$
\tau^</em> = \arg \min_{\tau \in C} \frac{1}{|Q|} \sum_{(r_i,p_i)\in Q} |r_i - I(p_i &lt; \tau)|$$
이 과정을 통해, PPL이 높음에도 정답인 샘플(CH)이나 PPL이 낮음에도 오답인 샘플(EL) 등 <strong>미세 조정이 필요한 타겟이 명확히 정의</strong>된다.</li>
</ol>
<h2 id="bidirectional-reward-reallocation-brr">Bidirectional Reward Reallocation (BRR)</h2>
<p>PSD를 통해 기준점 $\tau^<em>$를 찾았다면, 이를 바탕으로 *</em>보상을 재할당<strong>한다. BRR의 핵심은 모든 샘플의 보상을 건드리는 것이 아니라, **기울기가 0인 Hard/Easy 그룹 내에서 오직 &#39;최대 PPL&#39;을 가진 단일 샘플의 보상만 반전</strong>시킨다는 점이다.</p>
<ul>
<li><strong>Hard 그룹 업데이트 (탐색 유도):</strong> 그룹 내 보상이 모두 0이면서 평균 PPL이 $\tau^<em>$보다 낮은(EiS에 위치한) 경우, 그룹 내에서 *</em>가장 PPL이 높은 샘플 $m$의 보상을 $r_m^r = 1$로 재할당<strong>한다. 이는 모델이 **기존의 낮은 엔트로피 상태에서 벗어나 더 큰 불확실성(탐색)을 갖는 방향으로</strong> 정책을 업데이트하도록 유도한다.</li>
<li><strong>Easy 그룹 업데이트 (활용 유도):</strong> 그룹 내 보상이 모두 1이면서 평균 PPL이 $\tau^<em>$보다 높은(ErS에 위치한) 경우, 그룹 내에서 *</em>가장 PPL이 높은 샘플 $m$의 보상을 $r_m^r = 0$으로 재할당<strong>한다. 이는 이미 정답을 맞추는 그룹에 대해 **과도한 탐색을 억제하고 엔트로피를 낮추는 방향으로</strong> 유도한다.</li>
</ul>
<h2 id="학습-및-추론-파이프라인">학습 및 추론 파이프라인</h2>
<p>기존 검증 보상 $R$과 재할당된 보상 $R_r$은 <strong>직교성(Orthogonality)</strong>을 갖는다. 즉, BRR은 기울기가 0인 그룹만 활성화하므로 기존 RL 업데이트를 간섭하지 않는다.
최종 학습(Training) 목적 함수는 두 보상 체계에 대한 손실을 선형 결합하여 구성된다.
$$
J_{DiPO}(\theta) = J_{DAPO}(\theta, R) + \alpha \times J_{DAPO}(\theta, R_r)$$
여기서 $\alpha$는 <strong>재할당된 보상의 반영 비율을 조절</strong>하는 하이퍼파라미터다. 
추론(Inference) 단계에서는 별도의 추가 연산 없이, <strong>강화학습이 완료된 $\pi_\theta$ 정책 모델을 사용</strong>하여 일반적인 그리디 디코딩이나 샘플링을 수행한다.</p>
<hr>
<h1 id="3-실험-결과-experiments">3. 실험 결과 (Experiments)</h1>
<ul>
<li><strong>실험 세팅:</strong> 수학적 추론 능력 평가를 위해 DAPO-17K 데이터셋으로 학습하고 AIME24/25, MATH500 등 6개 벤치마크를 활용했다. 함수 호출 태스크는 ToolRL 프레임워크와 BFCLv3 벤치마크를 사용했다. 비교군(Baseline)으로는 GRPO, DAPO, DAPO w/ EL(Entropy Loss), CDE가 사용되었다.</li>
<li><strong>수학적 추론 결과:</strong> Qwen3-4B, 8B, Qwen2.5-7B 모델에서 모두 DiPO가 가장 높은 평균(AVG) 성능을 기록했다. 특히 Qwen3-8B-Base 모델 기준 AIME24에서 35.00%를 기록하며 기존 DAPO(30.08%) 대비 큰 폭의 상승을 보였다.</li>
<li><strong>함수 호출 결과:</strong> 다턴(Multi-Turn) 추론과 복잡한 환경이 요구되는 세팅에서 DiPO가 최고 성능(Qwen2.5-7B 기준 전체 정확도 62.51%)을 달성하여 태스크 범용성을 입증했다.</li>
<li><strong>해석 및 어블레이션:</strong> 실험 후반부의 성능 곡선(Learning Curve)을 분석한 결과, 기존 DAPO는 학습 후반부에 탐색을 멈추고 성능이 정체되는 반면, DiPO는 Hard 샘플에 대한 탐색 신호를 계속 제공하여 성능 한계치를 지속적으로 돌파했다. 또한, PPL을 직접 보상으로 사용하는 방식(CDE 유사 형태)은 오히려 베이스라인보다 성능이 하락하는 현상을 보여, BRR을 통한 직교적 보상 조정 설계가 학습 안정성에 필수적임이 증명되었다.</li>
</ul>
<hr>
<h1 id="4-한계점-및-시사점">4. 한계점 및 시사점</h1>
<h2 id="한계점">한계점</h2>
<ul>
<li><strong>명확한 검증 보상의 의존성:</strong> 본 방법론은 RLVR 환경, 즉 0 또는 1이라는 명확한 검증 보상(Verification Reward)이 존재하는 태스크(수학, 코딩, 특정 툴 사용)를 전제로 설계되었다. 정답이 명확하지 않은 오픈엔드 텍스트 생성이나 창의적 글쓰기 태스크에는 직접 적용하기 어렵다.</li>
<li><strong>추가적인 메모리 및 연산 오버헤드:</strong> 매 스텝 PPL Queue를 유지하고, $\tau^*$를 계산하며 통계적 유의성을 판별하는 작업은 표준 GRPO 대비 훈련 단계에서 미세한 연산/메모리 병목을 유발할 수 있다.</li>
</ul>
<h2 id="이론적-과제-및-시사점">이론적 과제 및 시사점</h2>
<ul>
<li><strong>하이퍼파라미터 민감도 완화:</strong> 기존의 단순 엔트로피 손실(Entropy Loss) 기법은 계수 변화에 따라 학습이 붕괴될 정도로 극도로 민감하지만, DiPO는 <strong>$\alpha$ 값 변화에 대해 훨씬 넓은 유효 범위</strong>를 가지며 안정성을 보였다. </li>
<li><strong>학술적/실무적 확장 가능성:</strong> 이 연구는 LLM의 RL 파인튜닝 과정에서 발생하는 <strong>&#39;보상 분포의 파괴 없이 탐색 능력을 주입하는 메커니즘&#39;</strong>의 우수 사례를 보여준다. 향후 오프라인(Offline) 데이터에 대한 PPL 사전 분석과 결합하거나, 가치 네트워크가 포함된 PPO 환경으로 이식하는 등 강화학습의 안정성과 탐색 범위를 넓히는 후속 연구로의 확장 가능성이 높다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>