Files
2nd/10_Wiki/Topics/AI_and_ML/Inverse-Kinematics.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

250 lines
7.4 KiB
Markdown

---
id: wiki-2026-0508-inverse-kinematics
title: Inverse Kinematics (IK)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [IK, inverse kinematics, FABRIK, Jacobian IK, CCD, robot arm]
duplicate_of: none
source_trust_level: A
confidence_score: 0.95
verification_status: applied
tags: [robotics, kinematics, ik, jacobian, fabrik, animation]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: Python / C++
framework: PyBullet / MoveIt / Unity Animation
---
# Inverse Kinematics (IK)
## 매 한 줄
> **"매 end-effector 의 target pose 의 의 의 joint angles 의 solve"**. 매 forward kinematics 의 reverse. 매 method: 매 analytic (closed-form), Jacobian (iterative), CCD, FABRIK. 매 응용: 매 robot, 매 animation, 매 VR avatar.
## 매 핵심
### 매 method
- **Analytic**: 매 closed-form (e.g., PUMA 6DOF).
- **Jacobian** pseudo-inverse / damped least squares.
- **Newton-Raphson**.
- **CCD** (Cyclic Coordinate Descent).
- **FABRIK** (Forward And Backward Reaching IK).
- **Optimization** (Nlopt, Drake).
### 매 challenge
- **Multiple solutions**.
- **Singularity** (near-singular pose).
- **Joint limits**.
- **Self-collision**.
- **Redundancy** (7+ DOF).
### 매 응용
1. **Robot manipulator**.
2. **Animation** (rigging, foot IK).
3. **VR avatar** (hand tracking).
4. **Motion capture cleanup**.
## 💻 패턴
### Jacobian-based IK
```python
import numpy as np
def jacobian_ik(forward_kinematics, target, q0, max_iter=200, tol=1e-3):
q = q0.copy()
for _ in range(max_iter):
p = forward_kinematics(q)[:3, 3]
err = target - p
if np.linalg.norm(err) < tol: return q
J = numerical_jacobian(forward_kinematics, q)
# 매 damped least squares (handles singularity)
lam = 0.01
dq = J.T @ np.linalg.solve(J @ J.T + lam ** 2 * np.eye(3), err)
q += dq * 0.1
return q
def numerical_jacobian(fk, q, eps=1e-6):
n = len(q)
p0 = fk(q)[:3, 3]
J = np.zeros((3, n))
for i in range(n):
q1 = q.copy(); q1[i] += eps
J[:, i] = (fk(q1)[:3, 3] - p0) / eps
return J
```
### CCD (Cyclic Coordinate Descent)
```python
def ccd(joints, target, n_iter=10):
"""매 매 joint 의 의 의 의 의 적용."""
for _ in range(n_iter):
end_effector = joints[-1].position
if np.linalg.norm(end_effector - target) < 1e-3: return joints
for i in range(len(joints) - 1, -1, -1):
joint = joints[i]
to_target = target - joint.position
to_end = end_effector - joint.position
angle = signed_angle_between(to_end, to_target)
joint.rotate(angle)
end_effector = joints[-1].position
return joints
```
### FABRIK
```python
def fabrik(joints, target, n_iter=10, tol=1e-3):
"""매 forward + backward iterative."""
base = joints[0].position
distances = [np.linalg.norm(joints[i+1].position - joints[i].position) for i in range(len(joints) - 1)]
for _ in range(n_iter):
# 매 backward (end → base)
joints[-1].position = target
for i in range(len(joints) - 2, -1, -1):
d = joints[i+1].position - joints[i].position
d = d / np.linalg.norm(d) * distances[i]
joints[i].position = joints[i+1].position - d
# 매 forward (base → end)
joints[0].position = base
for i in range(len(joints) - 1):
d = joints[i+1].position - joints[i].position
d = d / np.linalg.norm(d) * distances[i]
joints[i+1].position = joints[i].position + d
if np.linalg.norm(joints[-1].position - target) < tol: break
return joints
```
### Analytic IK (PUMA-style)
```python
def puma_ik_closed(target_pose, link_lengths):
"""매 closed-form for 6-DOF PUMA. 매 simplified."""
x, y, z = target_pose[:3, 3]
l1, l2, l3 = link_lengths
theta1 = np.arctan2(y, x)
r = np.sqrt(x**2 + y**2)
s = z - l1
# 매 elbow up / down
cos_theta3 = (r**2 + s**2 - l2**2 - l3**2) / (2 * l2 * l3)
theta3 = np.arccos(np.clip(cos_theta3, -1, 1))
theta2 = np.arctan2(s, r) - np.arctan2(l3 * np.sin(theta3), l2 + l3 * np.cos(theta3))
return [theta1, theta2, theta3] # 매 + theta4-6 from orientation
```
### Damped least squares (singularity-robust)
```python
def damped_ls_ik(J, err, lam=0.01):
n = J.shape[1]
return J.T @ np.linalg.solve(J @ J.T + lam**2 * np.eye(J.shape[0]), err)
```
### Animation foot IK (Unity-style)
```csharp
// Unity AnimatorIK
void OnAnimatorIK(int layer) {
animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, 1.0f);
animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, 1.0f);
Vector3 footTarget = GetFootTarget(); // 매 raycast for ground
animator.SetIKPosition(AvatarIKGoal.LeftFoot, footTarget);
}
```
### Joint limit handling
```python
def clamp_to_limits(q, lower_limits, upper_limits):
return np.clip(q, lower_limits, upper_limits)
```
### Null-space (redundancy)
```python
def null_space_ik(J, err, secondary_obj, q):
"""매 7-DOF — 매 primary task + secondary (e.g., avoid joint limit)."""
J_pinv = np.linalg.pinv(J)
primary = J_pinv @ err
null_proj = np.eye(len(q)) - J_pinv @ J
secondary = null_proj @ secondary_obj(q)
return primary + secondary
```
### MoveIt (ROS)
```python
import moveit_commander
moveit_commander.roscpp_initialize([])
arm = moveit_commander.MoveGroupCommander('manipulator')
target_pose = PoseStamped()
target_pose.pose.position.x = 0.4
target_pose.pose.position.y = 0.0
target_pose.pose.position.z = 0.5
arm.set_pose_target(target_pose)
plan = arm.plan()
arm.execute(plan)
```
### IK with collision check
```python
def ik_with_collision(target, robot, obstacles):
q = jacobian_ik(target, q0=robot.current_q)
if check_collision(robot, q, obstacles):
# 매 try alternative IK solution
for alt in alternative_solutions(target, robot):
if not check_collision(robot, alt, obstacles): return alt
return None
return q
```
### Hand tracking IK (VR)
```python
def hand_ik(wrist_target_pose, fingers, hand_model):
"""매 VR 매 wrist 의 의 의 의 의 fingers 의 IK."""
arm_q = jacobian_ik(hand_model.arm_fk, wrist_target_pose)
finger_qs = [fabrik(f.joints, target=wrist_target_pose @ f.local_target) for f in fingers]
return arm_q, finger_qs
```
## 매 결정 기준
| 상황 | Method |
|---|---|
| Standard 6-DOF | Analytic (Pieper) |
| Singularity-prone | Damped LS |
| Animation chain | FABRIK / CCD |
| Robot with collision | Optimization + collision check |
| Redundant 7-DOF | Null-space |
| Real-time game | CCD / FABRIK |
**기본값**: 매 robot = damped LS Jacobian. 매 animation = FABRIK / CCD. 매 ROS = MoveIt. 매 always check joint limits + collision.
## 🔗 Graph
- 부모: [[Robotics]]
- 변형: [[FABRIK]] · [[CCD]]
- Adjacent: [[Denavit-Hartenberg-Parameters]] · [[Degrees-of-Freedom]]
## 🤖 LLM 활용
**언제**: 매 robot manipulator. 매 animation. 매 VR.
**언제 X**: 매 mobile-base-only.
## ❌ 안티패턴
- **Pseudo-inverse near singularity**: 매 explode.
- **Ignore joint limits**: 매 invalid.
- **Single solution**: 매 multiple — pick best.
- **No collision check**: 매 hardware damage.
## 🧪 검증 / 중복
- Verified (Spong Robot Dynamics, Aristidou FABRIK 2011).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — methods + 매 Jacobian / CCD / FABRIK / null-space code |