📐 Математика движения

Урок 3.1 | Level 3: Инженер

Кинематика — язык робототехники

Главный вопрос

У робота-манипулятора 3 сустава с моторами.

Прямая задача (FK):
Моторы повёрнуты на углы $\theta_1=30°$, $\theta_2=45°$, $\theta_3=60°$.
Где находится схват?

Обратная задача (IK):
Нужно взять объект в точке $(x, y, z) = (10, 5, 3)$ см.
На какие углы повернуть моторы?

Прямая кинематика (Forward Kinematics)

Простейший случай: 2D рука с 2 звеньями

         (x, y)
         ╱ L₂
       ● θ₂
     ╱ L₁
   ● θ₁
───┴───  (база)

Формулы FK для 2D

Положение конца манипулятора:

$$ x = L_1 \cos(\theta_1) + L_2 \cos(\theta_1 + \theta_2) $$$$ y = L_1 \sin(\theta_1) + L_2 \sin(\theta_1 + \theta_2) $$

Это просто тригонометрия! 📐

Код FK на Python

import math

def forward_kinematics(L1, L2, theta1, theta2):
    """
    Прямая кинематика для 2-звенного манипулятора
    L1, L2 - длины звеньев (см)
    theta1, theta2 - углы (радианы)
    """
    x = L1 * math.cos(theta1) + L2 * math.cos(theta1 + theta2)
    y = L1 * math.sin(theta1) + L2 * math.sin(theta1 + theta2)
    return x, y

# Пример
L1, L2 = 10, 8  # см
theta1 = math.radians(30)
theta2 = math.radians(45)

x, y = forward_kinematics(L1, L2, theta1, theta2)
print(f"Позиция: ({x:.2f}, {y:.2f}) см")

FK для 3D: Матрицы преобразований

В 3D используем однородные матрицы 4×4:

$$ T = \begin{bmatrix} R_{3\times3} & p_{3\times1} \\ 0_{1\times3} & 1 \end{bmatrix} $$

где $R$ — матрица вращения, $p$ — вектор смещения.

DH-параметры (Денавита-Хартенберга)

Стандартный способ описать кинематику:

ПараметрЗначение
$a_i$Длина звена
$\alpha_i$Угол поворота оси
$d_i$Смещение по оси
$\theta_i$Угол в суставе (переменная!)
Сустав 1: a=0, α=90°, d=0, θ=θ₁
Сустав 2: a=L1, α=0°, d=0, θ=θ₂
...

Обратная кинематика (Inverse Kinematics)

Почему это сложнее?

FK: Одно решение (всегда!)
IK: 0, 1, 2 или бесконечно решений!

Точка недостижима:        Два решения:
                          
    ●                         ●
    (слишком далеко)       ╱   ╲
                          ╱     ╲
    ●───●                ╱       ╲
    (робот)             (локоть вверх/вниз)

Геометрическое решение для 2D

Используем теорему косинусов:

         ●(x, y)
        ╱╲
    L₂ ╱  ╲ ?
      ╱    ╲
     ●      ╲
    ╱        ╲
L₁ ╱          ╲
  ╱            ╲
 ●──────────────
      d = √(x² + y²)

Формулы IK для 2D

$$ d = \sqrt{x^2 + y^2} $$$$ \cos(\theta_2) = \frac{d^2 - L_1^2 - L_2^2}{2 L_1 L_2} $$$$ \theta_2 = \pm \arccos\left(\frac{d^2 - L_1^2 - L_2^2}{2 L_1 L_2}\right) $$

Знак ± даёт два решения!

Формулы IK (продолжение)

$$ \theta_1 = \arctan2(y, x) - \arctan2(L_2 \sin\theta_2, L_1 + L_2 \cos\theta_2) $$

Код IK на Python

def inverse_kinematics(L1, L2, x, y, elbow_up=True):
    """
    Обратная кинематика для 2-звенного манипулятора
    elbow_up: True = локоть вверх, False = локоть вниз
    """
    d_sq = x**2 + y**2
    d = math.sqrt(d_sq)
    
    # Проверка достижимости
    if d > L1 + L2 or d < abs(L1 - L2):
        raise ValueError("Точка недостижима!")
    
    # Угол локтя
    cos_theta2 = (d_sq - L1**2 - L2**2) / (2 * L1 * L2)
    theta2 = math.acos(cos_theta2)
    if not elbow_up:
        theta2 = -theta2
    
    # Угол плеча
    alpha = math.atan2(y, x)
    beta = math.atan2(L2 * math.sin(theta2), L1 + L2 * math.cos(theta2))
    theta1 = alpha - beta
    
    return theta1, theta2

Проверка: FK(IK(x,y)) == (x,y)?

# Тест
x_target, y_target = 12, 8
theta1, theta2 = inverse_kinematics(10, 8, x_target, y_target)
x_result, y_result = forward_kinematics(10, 8, theta1, theta2)

print(f"Цель: ({x_target}, {y_target})")
print(f"Результат: ({x_result:.4f}, {y_result:.4f})")
# Должны совпадать!

Системы координат и TF

Зачем нужны разные системы координат?

       Камера видит объект          Рука должна схватить
       в своих координатах          в своих координатах
             │                            │
             ▼                            ▼
        ┌─────────┐                 ┌─────────┐
        │ Камера  │ ─── TF ───────► │  Рука   │
        │ (x,y,z) │   transform     │ (x,y,z) │
        └─────────┘                 └─────────┘

TF (Transform) — преобразование между системами координат.

Иерархия фреймов в ROS 2

                    map
                   odom
                 base_link
                ╱    │    ╲
               ▼     ▼     ▼
           camera  lidar  arm_base
                        arm_link1
                        arm_link2
                         gripper

Преобразование координат

$$ P_{camera} = (x_c, y_c, z_c) $$$$ T_{base \leftarrow camera} $$$$ P_{base} = T_{base \leftarrow camera} \cdot P_{camera} $$

Практика: Симулятор манипулятора

Интерактивная демо

# Визуализация с matplotlib
import matplotlib.pyplot as plt
import numpy as np

def draw_arm(L1, L2, theta1, theta2):
    # Позиции суставов
    x0, y0 = 0, 0
    x1 = L1 * np.cos(theta1)
    y1 = L1 * np.sin(theta1)
    x2, y2 = forward_kinematics(L1, L2, theta1, theta2)
    
    plt.figure(figsize=(8, 8))
    plt.plot([x0, x1, x2], [y0, y1, y2], 'o-', linewidth=3)
    plt.xlim(-20, 20)
    plt.ylim(-5, 20)
    plt.grid(True)
    plt.axis('equal')
    plt.title(f'θ1={np.degrees(theta1):.1f}°, θ2={np.degrees(theta2):.1f}°')
    plt.show()

Рабочая зона манипулятора

# Визуализация рабочей зоны
theta1_range = np.linspace(0, np.pi, 50)
theta2_range = np.linspace(-np.pi, np.pi, 50)

points = []
for t1 in theta1_range:
    for t2 in theta2_range:
        x, y = forward_kinematics(10, 8, t1, t2)
        points.append((x, y))

xs, ys = zip(*points)
plt.scatter(xs, ys, s=1, alpha=0.5)
plt.title('Рабочая зона манипулятора')
plt.axis('equal')
plt.show()

Связь с физикой

Это школьная тригонометрия + векторы!

Школьная темаПрименение в робототехнике
$\sin$, $\cos$Позиция звеньев
Теорема косинусовОбратная кинематика
ВекторыПоложение и скорость
МатрицыПреобразования координат

Подробнее в справочнике

📚 Кинематика FK/IK
📚 Системы координат TF
📚 Степени свободы DoF

Следующий урок

🔮 Слияние датчиков

Урок 3.2 →

Как объединить данные с нескольких датчиков и получить истину!