Files
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

7.4 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-inverse-kinematics Inverse Kinematics (IK) 10_Wiki/Topics verified self
IK
inverse kinematics
FABRIK
Jacobian IK
CCD
robot arm
none A 0.95 applied
robotics
kinematics
ik
jacobian
fabrik
animation
2026-05-10 pending
language framework
Python / C++ 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

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)

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

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)

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)

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)

// 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

def clamp_to_limits(q, lower_limits, upper_limits):
    return np.clip(q, lower_limits, upper_limits)

Null-space (redundancy)

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)

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

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)

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

🤖 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