[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,89 +1,250 @@
|
||||
---
|
||||
id: wiki-2026-0508-inverse-kinematics
|
||||
title: Inverse Kinematics
|
||||
title: Inverse Kinematics (IK)
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AI-INVERSE-KINEMATICS]
|
||||
aliases: [IK, inverse kinematics, FABRIK, Jacobian IK, CCD, robot arm]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.97
|
||||
tags: ["Robotics|[Robotics", Kinematics, Animation, Mathematics]
|
||||
confidence_score: 0.95
|
||||
verification_status: applied
|
||||
tags: [robotics, kinematics, ik, jacobian, fabrik, animation]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: Python / C++
|
||||
framework: PyBullet / MoveIt / Unity Animation
|
||||
---
|
||||
|
||||
# [[Inverse-Kinematics|Inverse-Kinematics]] (역운동학)
|
||||
# Inverse Kinematics (IK)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "손의 위치를 결정하면, 팔꿈치와 어깨가 알아서 굽혀지는 마법." 로봇이나 캐릭터의 끝단(End-effector)의 목표 위치가 주어졌을 때, 그 상태에 도달하기 위한 각 관절의 각도들을 거꾸로 계산해내는 과정이다.
|
||||
## 매 한 줄
|
||||
> **"매 end-effector 의 target pose 의 의 의 joint angles 의 solve"**. 매 forward kinematics 의 reverse. 매 method: 매 analytic (closed-form), Jacobian (iterative), CCD, FABRIK. 매 응용: 매 robot, 매 animation, 매 VR avatar.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Forward vs Inverse**:
|
||||
- **Forward**: 관절 각도 $\to$ 손의 위치 (계산이 쉽고 결과가 하나임).
|
||||
- **Inverse**: 손의 위치 $\to$ 관절 각도 (수학적으로 매우 복잡하며, 해가 여러 개이거나 없을 수 있음).
|
||||
- **Solving Methods**:
|
||||
- **Analytical**: 수식으로 딱 떨어지는 정답을 구함 (속도가 빠르지만 단순한 로봇만 가능).
|
||||
- **Numerical (Iterative)**: 조금씩 각도를 바꿔보며 정답에 근접함 (자코비안 행렬, FABRIK 등 사용).
|
||||
- **Core Benefit**: 사람이 일일이 관절을 조종하지 않고 "저 컵을 잡아"라고 명령만 내릴 수 있게 함.
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 역운동학은 장애물 충돌이나 관절의 물리적 한계를 고려해야 하므로 갈수록 복잡해진다. 최근에는 신경망 기반의 IK 솔버나 강화학습 에이전트가 물리 시뮬레이션 환경에서 스스로 '가장 자연스러운 포즈'를 학습하여, 고전적인 수치 해석 방식의 한계를 넘어서는 자연스러운 움직임을 보여주고 있다.
|
||||
### 매 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).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: Denavit-Hartenberg-Parameters , [[Robotics|Robotics]]
|
||||
- Algorithm: FABRIK-Algorithm
|
||||
### 매 challenge
|
||||
- **Multiple solutions**.
|
||||
- **Singularity** (near-singular pose).
|
||||
- **Joint limits**.
|
||||
- **Self-collision**.
|
||||
- **Redundancy** (7+ DOF).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
1. **Robot manipulator**.
|
||||
2. **Animation** (rigging, foot IK).
|
||||
3. **VR avatar** (hand tracking).
|
||||
4. **Motion capture cleanup**.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
### Jacobian-based IK
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
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
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
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
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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)
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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);
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### 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]] · [[Kinematics]]
|
||||
- 변형: [[Forward-Kinematics]] · [[FABRIK]] · [[CCD]]
|
||||
- 응용: [[MoveIt]] · [[Animation-Rigging]] · [[VR-Avatar]]
|
||||
- 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 |
|
||||
|
||||
Reference in New Issue
Block a user