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