개요
로봇 팔을 원하는 위치로 이동시키는 방법은 크게 두 가지로 나뉩니다.
- 간접 호출: MoveGroup Action Server에 목표만 전달하면 나머지를 알아서 처리
- 직접 호출:
/compute_ik서비스로 관절각만 계산받고, 실행은 직접 제어
핵심 차이: 간접은 **"어디로 갈지"**만 말하면 되고, 직접은 **"어떻게 갈지"**를 내가 책임진다.
이 포스트에서는 두 방식의 내부 동작, 성능 차이, 그리고 상황별 선택 기준을 정리합니다.
간접 호출 — MoveGroup
MoveGroup은 MoveIt의 핵심 Action Server로, 목표 Pose 하나만 넘기면 IK 계산부터 경로 계획, 충돌 검사, 궤적 실행까지 전부 처리합니다.
flowchart TD
A["목표 Pose 전달"] --> B["MoveGroup Action Server"]
B --> C["① IK로 목표 관절각 계산"]
C --> D["② OMPL 플래너로 경로 계획"]
D --> E["③ 충돌 검사"]
E --> F["④ 시간 파라미터화 (Time Parameterization)"]
F --> G["⑤ 전체 궤적(Trajectory) 완성"]
G --> H["ExecuteTrajectory로 실행"]
style B fill:#4a90d9,color:#fff
style H fill:#27ae60,color:#fff| 단계 | 설명 |
|---|---|
| IK (Inverse Kinematics) | 목표 Pose → 관절각 변환. KDL, TRAC-IK 등의 솔버 사용 |
| 경로 계획 | 현재 관절각 → 목표 관절각까지의 경로를 OMPL(RRT, RRT* 등)로 탐색 |
| 충돌 검사 | Planning Scene의 장애물과 자기 자신(self-collision) 검사 |
| 시간 파라미터화 | 경로의 각 웨이포인트에 속도·가속도 제한을 적용하여 실행 가능한 궤적으로 변환 |
| 궤적 실행 | FollowJointTrajectory 액션으로 컨트롤러에 전달 |
import rclpy
from moveit_commander import MoveGroupCommander
# MoveGroup 초기화
group = MoveGroupCommander("manipulator")
# 목표 Pose 설정
target_pose = group.get_current_pose().pose
target_pose.position.x = 0.3
target_pose.position.z = 0.5
# 한 번의 호출로 계획 + 실행 완료
group.set_pose_target(target_pose)
plan = group.go(wait=True) # IK → 경로계획 → 충돌검사 → 실행까지 전부 수행
group.stop()
group.clear_pose_targets()특징: 한 번 호출하면 IK + 경로계획 + 실행까지 다 해준다. 편하지만 1~5초 소요.
직접 호출 — /compute_ik
/compute_ik 서비스는 IK 계산만 수행합니다. 경로 계획도 없고, 충돌 검사도 없습니다. 결과로 관절각만 반환되며, 이를 컨트롤러에 직접 발행하는 것은 개발자의 몫입니다.
flowchart TD
A["목표 Pose 전달"] --> B["/compute_ik 서비스"]
B --> C["① IK로 목표 관절각 계산"]
C --> D["② 관절각 반환 (끝)"]
D --> E["개발자가 직접 컨트롤러에 발행"]
style B fill:#e67e22,color:#fff
style E fill:#e74c3c,color:#fffimport rclpy
from rclpy.node import Node
from moveit_msgs.srv import GetPositionIK
from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
class DirectController(Node):
def __init__(self):
super().__init__('direct_controller')
# IK 서비스 클라이언트
self.ik_client = self.create_client(GetPositionIK, '/compute_ik')
# 관절 명령 퍼블리셔
self.joint_pub = self.create_publisher(
JointTrajectory, '/joint_trajectory_controller/joint_trajectory', 10
)
# 30Hz 제어 루프
self.timer = self.create_timer(1.0 / 30.0, self.control_loop)
self.target_pose = None # 외부에서 설정
def control_loop(self):
if self.target_pose is None:
return
# ① IK로 관절각만 빠르게 계산 (~50ms)
request = GetPositionIK.Request()
request.ik_request.pose_stamped.pose = self.target_pose
request.ik_request.group_name = "manipulator"
future = self.ik_client.call_async(request)
# ... 응답 처리 후 관절각을 컨트롤러에 직접 발행# 실시간 제어의 핵심 — 30Hz 루프 안에서 조금씩 이동
target.position.x += 0.001 # 1mm씩 이동
joints = compute_ik(target) # 관절각만 빠르게 계산 (~50ms)
publish(joints) # 직접 컨트롤러에 발행특징: IK만 풀어주므로 ~50ms로 매우 빠르다. 실시간 제어에 적합.
비교 정리
| 항목 | 간접 호출 (MoveGroup) | 직접 호출 (/compute_ik) |
|---|---|---|
| 비유 | 내비 켜고 경로 안내받아 운전 | 목적지 방향만 알고 직접 운전 |
| IK 계산 | 내부에서 자동 수행 | 직접 서비스 호출 |
| 경로 계획 | O (장애물 회피 포함) | X |
| 충돌 검사 | O | X |
| 속도 | 느림 (1~5초) | 빠름 (~50ms) |
| 제어 주기 | 1회성 | 30Hz 반복 가능 |
| 용도 | "저기로 안전하게 가" | "조금씩 실시간으로 이동" |
| 안전성 | 높음 (자동 검증) | 낮음 (개발자 책임) |
flowchart LR
subgraph 간접호출["간접 호출 (MoveGroup)"]
direction TB
A1["IK"] --> A2["경로 계획"]
A2 --> A3["충돌 검사"]
A3 --> A4["궤적 실행"]
end
subgraph 직접호출["직접 호출 (/compute_ik)"]
direction TB
B1["IK"] --> B2["관절각 반환"]
B2 --> B3["직접 제어"]
end
간접호출 -.- 직접호출
style 간접호출 fill:#eaf2ff,stroke:#4a90d9
style 직접호출 fill:#fff5eb,stroke:#e67e22언제 무엇을 쓸까?
- 목표 지점이 현재 위치에서 먼 경우
- 작업 공간에 장애물이 존재하는 경우
- 안전성이 중요한 환경 (산업 현장, 협동 로봇)
- Pick & Place처럼 정확한 도달이 중요한 작업
- 실시간 추적이 필요한 경우 (비주얼 서보잉, 물체 추적)
- 텔레오퍼레이션 (원격 조종) 시 조이스틱/마우스 입력을 즉시 반영해야 할 때
- 미세 조정이 필요한 경우 (표면 따라가기, 힘 제어)
- 장애물이 없는 안전한 환경에서 빠른 반응이 필요할 때
stateDiagram-v2
[*] --> 판단
판단 --> 간접호출 : 장애물 있음 / 먼 거리
판단 --> 직접호출 : 장애물 없음 / 실시간 필요
간접호출 --> MoveGroup : plan + execute
직접호출 --> compute_ik : IK만 계산
compute_ik --> 컨트롤러발행 : 직접 publish
MoveGroup --> [*]
컨트롤러발행 --> [*]실전 팁
- 직접 호출 시 충돌 방지:
/compute_ik는 충돌 검사를 하지 않으므로, 필요하다면planning_scene모니터를 별도로 구성하여 관절각이 충돌 상태인지 사전 검증하세요. - 하이브리드 접근: 먼 거리는 MoveGroup으로 대략 이동한 뒤, 미세 조정은
/compute_ik로 전환하는 하이브리드 전략이 실전에서 자주 사용됩니다. - IK 솔버 선택: TRAC-IK는 KDL보다 성공률이 높고 빠릅니다. 직접 호출을 많이 쓴다면
kinematics.yaml에서 솔버를 TRAC-IK로 변경하는 것을 권장합니다. - 속도 제한 설정: 직접 호출에서 관절 속도 제한을 코드 레벨에서 반드시 적용하세요. 급격한 관절각 변화는 로봇 손상의 원인이 됩니다.
핵심 요약
| 간접 호출 | 직접 호출 | |
|---|---|---|
| 한 줄 요약 | "어디로 갈지"만 말하면 된다 | "어떻게 갈지"를 내가 책임진다 |
| 장점 | 안전하고 편리함 | 빠르고 유연함 |
| 단점 | 느리고 실시간 제어 불가 | 충돌 검사 없음, 안전은 개발자 몫 |
간접 호출은 안전한 자동 운전, 직접 호출은 빠른 수동 운전이다. 상황에 맞게 선택하고, 필요하면 둘을 조합하는 하이브리드 방식을 활용하자.