로봇공학기초

[로봇공학기초 / 2DOF] #5. Singularity (특이점)

jhpark0518 2025. 4. 4. 10:00

⚠️ 특이점(Singularity)이란?

지난 글에서는 자코비안 행렬(Jacobian Matrix)을 이용해
로봇팔의 말단 속도를 계산하는 방법을 알아보았습니다.

이번에는 로봇공학에서 매우 중요한 개념인 특이점(Singularity)에 대해 정리해보겠습니다.

특이점은 종종 로봇이 잘 움직이지 못하는 지점라고 설명되지만, 더 정확하게 말하면 다음과 같습니다:

“우리가 원하는 말단 속도를 만들기 위해 관절 속도를 계산할 수 없는 지점”

이는 속도 역기구학(Inverse Velocity Kinematics)이 실패하는 지점입니다.수학적으로는 자코비안 행렬 \( J \)의 행렬식(det)이 0이 되는 지점에서 발생하며,이 경우 역행렬 \( J^{-1} \)이 존재하지 않게 됩니다.

 

✋ 특이점은 어떤 상황일까?

우리는 로봇을 제어할 때 보통 말단(End-effector)의 움직임을 먼저 정합니다.
즉, "끝점이 직선으로 이렇게 이동했으면 좋겠다"는 식으로 카테시안 공간 기준의 속도 \( \dot{x} \) 를 정합니다.

하지만 실제로 로봇을 움직이게 만들기 위해선 그 움직임을 만들어줄 관절 속도 \( \dot{\theta} \) 가 필요하죠.
이때 사용하는 것이 자코비안:

$$
\dot{x} = J(\theta)\dot{\theta}
$$

이걸 역으로 계산해서 관절을 제어해야 합니다:

$$
\dot{\theta} = J^{-1}(\theta)\dot{x}
$$

그런데 문제는, 특이점에서는 \( J^{-1} \) 존재하지 않습니다.
즉, 아무리 말단을 움직이고 싶어도, 그걸 실현할 수 있는 관절 속도가 존재하지 않거나 무한대가 되는 지점이 바로 특이점입니다.

 

📌 쉽게 말해 이런 상황입니다:

  • 우리는 "말단을 이렇게 움직여줘!"라고 명령했는데,
  • 로봇은 "그렇게 움직이려면 관절이 무한히 빨라야 합니다…" 라는 불가능한 답을 내놓는 상태

이런 이유로 특이점에서는 속도 제어가 불가능하거나,
움직임이 극도로 민감하고 불안정해지며,
실제로 로봇이 멈추거나 튀는 현상이 발생할 수 있습니다.

 

📐 2자유도 로봇팔의 자코비안 행렬과 특이점 조건 유도

두 관절을 가진 2자유도 평면 로봇팔의 자코비안 행렬은 다음과 같습니다:

$$ J(\theta_1, \theta_2) = \begin{bmatrix} -L_1 \sin{\theta_1} - L_2 \sin{(\theta_1 + \theta_2)} & -L_2 \sin{(\theta_1 + \theta_2)} \\ L_1 \cos{\theta_1} + L_2 \cos{(\theta_1 + \theta_2)} & L_2 \cos{(\theta_1 + \theta_2)} \end{bmatrix} $$

이 행렬의 행렬식은 다음과 같이 단순화됩니다:

$$ \det(J) = L_1 L_2 \sin{\theta_2} $$

따라서 행렬식이 0인 다음 두 경우에 특이점이 발생합니다:

  • \( \theta_2 = 0 \): 로봇팔이 완전히 펼쳐진 경우
  • \( \theta_2 = \pi \): 로봇팔이 완전히 접힌 경우

💻 특이점 시각화 Python 코드

import numpy as np
import matplotlib.pyplot as plt

# 한글 폰트 설정
plt.rcParams['font.family'] = 'NanumGothic'
plt.rcParams['axes.unicode_minus'] = False

# 자코비안 행렬식
def det_jacobian(theta2, l1=1.0, l2=0.5):
    return l1 * l2 * np.sin(theta2)

# Forward kinematics
def forward_kinematics(theta1, theta2, l1, l2):
    joint = np.array([l1 * np.cos(theta1), l1 * np.sin(theta1)])
    end_effector = joint + np.array([l2 * np.cos(theta1 + theta2), l2 * np.sin(theta1 + theta2)])
    return np.array([0, 0]), joint, end_effector

# 현재 설정
l1, l2 = 1.0, 0.5
theta1_cur = np.deg2rad(121.5)
theta2_cur = np.deg2rad(41.4)

# 현재 로봇팔 위치 계산
base, joint, end_effector = forward_kinematics(theta1_cur, theta2_cur, l1, l2)

# 특이점 조건: sin(theta2) = 0 → theta2 = 0, pi
theta1_range = np.linspace(-np.pi, np.pi, 400)
singularity_points = []

for theta1 in theta1_range:
    for theta2 in [0, np.pi]:  # 특이점이 일어나는 두 지점
        _, _, ee = forward_kinematics(theta1, theta2, l1, l2)
        singularity_points.append(ee)

singularity_points = np.array(singularity_points)

# 시각화
fig, ax = plt.subplots(figsize=(6, 6), dpi=150)

# 특이점 위치 그리기
ax.scatter(singularity_points[:, 0], singularity_points[:, 1], color='red', s=15, label='특이점 위치')

# 현재 로봇팔 자세
ax.plot([base[0], joint[0], end_effector[0]],
        [base[1], joint[1], end_effector[1]],
        'ko-', linewidth=2, markersize=8, label='현재 로봇팔')

# 마커 및 텍스트
ax.plot(base[0], base[1], 'ks', markersize=10)
ax.text(end_effector[0]+0.05, end_effector[1]+0.05, "End-Effector", fontsize=9)

# 스타일
ax.set_title("특이점 위치 (det(J) = 0) 및 현재 로봇팔 자세")
ax.set_xlabel("X (m)")
ax.set_ylabel("Y (m)")
ax.set_xlim(-2, 2)   # ✅ X축 범위 고정
ax.set_ylim(-2, 2)   # ✅ Y축 범위 고정
ax.legend()
ax.grid(True)
plt.tight_layout()
plt.savefig("singularity_points_with_arm.png", dpi=300)
plt.show()

🔧 실행 환경

  • Python 3.8 이상
  • numpy
  • matplotlib
  • Jupyter Notebook (추천)

📘 다음 편 예고

2자유도 평면 로봇팔의 자코비안 행렬을 이용해, 특이점(Singularity)이 발생하는 수학적 조건과 그 의미를 직관적으로 해석해보았습니다. 다음 글에서는 Trajectory Planning(궤적 생성)에 대해 알아보겠습니다. 로봇이 시작점에서 목표점까지 움직이는 경로를 어떻게 설계하는지, 다양한 궤적 생성 기법들을 소개할 예정입니다.