📐 Кинематика — FK и IK
Кинематика отвечает на главные вопросы робототехники:
- Где окажется рука робота, если я поверну моторы на определённые углы?
- На какие углы повернуть моторы, чтобы рука попала в нужную точку?
1. Прямая кинематика (Forward Kinematics — FK)
“От моторов к координатам”
[Углы моторов] → [Формулы] → [Координаты X, Y, Z]
Пример: 2D-манипулятор
(x, y) — конец руки
╱
╱ L2 (локоть → кисть)
╱
● θ2 (угол в локте)
╱
╱ L1 (плечо → локоть)
╱
● θ1 (угол в плече)
║
╨ основание
Формулы:
x = L1 × cos(θ1) + L2 × cos(θ1 + θ2)
y = L1 × sin(θ1) + L2 × sin(θ1 + θ2)
Код на Python
import math
# Длины звеньев (см)
L1, L2 = 15, 10
# Углы (градусы → радианы)
theta1 = math.radians(30) # Плечо
theta2 = math.radians(45) # Локоть
# Прямая кинематика
x = L1 * math.cos(theta1) + L2 * math.cos(theta1 + theta2)
y = L1 * math.sin(theta1) + L2 * math.sin(theta1 + theta2)
print(f"Кисть в точке: ({x:.1f}, {y:.1f}) см")
# Результат: Кисть в точке: (20.1, 14.7) см
Особенность FK: У задачи всегда один правильный ответ.
2. Обратная кинематика (Inverse Kinematics — IK)
“От координат к моторам”
[Координаты X, Y, Z] → [Сложные формулы] → [Углы моторов]
Почему IK сложнее?
| Проблема | Описание |
|---|---|
| Несколько решений | Локоть можно согнуть вверх или вниз |
| Нет решения | Точка слишком далеко — робот не дотянется |
| Сингулярность | Рука “заклинивает” в некоторых позах |
Пример: два решения IK
Решение 1: "локоть вверх" Решение 2: "локоть вниз"
● ●
╱ ╲
╱ ╲
● цель ✕ ●
╲ ╱ ╱
╲ ╱ ╱
●────● ●────●
Оба положения достигают одной точки!
Код на Python (для 2D)
import math
def inverse_kinematics(x, y, L1, L2):
"""Обратная кинематика для 2D-манипулятора"""
# Проверяем достижимость
dist = math.sqrt(x**2 + y**2)
if dist > L1 + L2:
return None # Слишком далеко!
if dist < abs(L1 - L2):
return None # Слишком близко!
# Угол локтя (теорема косинусов)
cos_theta2 = (x**2 + y**2 - L1**2 - L2**2) / (2 * L1 * L2)
theta2 = math.acos(cos_theta2) # "Локоть вниз"
# theta2 = -math.acos(cos_theta2) # "Локоть вверх"
# Угол плеча
k1 = L1 + L2 * math.cos(theta2)
k2 = L2 * math.sin(theta2)
theta1 = math.atan2(y, x) - math.atan2(k2, k1)
return math.degrees(theta1), math.degrees(theta2)
# Пример
result = inverse_kinematics(x=20, y=10, L1=15, L2=10)
if result:
print(f"Углы: плечо = {result[0]:.1f}°, локоть = {result[1]:.1f}°")
else:
print("Точка недостижима!")
3. Сравнение FK и IK
| Характеристика | FK (прямая) | IK (обратная) |
|---|---|---|
| Вход | Углы моторов | Координаты точки |
| Выход | Координаты | Углы моторов |
| Сложность | Простая | Сложная |
| Решений | Всегда одно | 0, 1 или несколько |
| Применение | Симуляция | Управление роботом |
4. Когда что использовать?
FK — прямая кинематика
- Симуляция: “Если поверну мотор на 10°, куда попадёт рука?”
- Визуализация: Показать текущее положение робота
- Проверка: Убедиться, что IK рассчитан правильно
IK — обратная кинематика
- Управление: “Робот, возьми предмет в точке (X, Y)”
- Траектории: Рассчитать путь руки по линии
- Слежение: Робот следит камерой за объектом
5. Практика для школьных проектов
Уровень 1: Картонный манипулятор
Материалы: Картон, кнопки (шарниры), транспортир
Задание:
- Вырежьте 2 звена: L1 = 15 см, L2 = 10 см
- Соедините кнопками
- Установите θ1 = 30°, θ2 = 45°
- Измерьте, где оказалась “кисть”
- Сравните с расчётом по формуле
Уровень 2: Arduino-манипулятор
#include <Servo.h>
#include <math.h>
Servo shoulder, elbow;
const float L1 = 15.0, L2 = 10.0;
void setup() {
shoulder.attach(9);
elbow.attach(10);
}
// Обратная кинематика
bool moveToXY(float x, float y) {
float dist = sqrt(x*x + y*y);
if (dist > L1 + L2) return false; // Недостижимо
float cos_theta2 = (x*x + y*y - L1*L1 - L2*L2) / (2*L1*L2);
if (abs(cos_theta2) > 1) return false;
float theta2 = acos(cos_theta2);
float k1 = L1 + L2 * cos(theta2);
float k2 = L2 * sin(theta2);
float theta1 = atan2(y, x) - atan2(k2, k1);
// Преобразуем радианы в градусы для сервоприводов
int angle1 = (int)(theta1 * 180 / PI) + 90; // Сдвиг на 90° для серво
int angle2 = (int)(theta2 * 180 / PI);
shoulder.write(constrain(angle1, 0, 180));
elbow.write(constrain(angle2, 0, 180));
return true;
}
void loop() {
moveToXY(20, 10); // Переместить в точку (20, 10)
delay(2000);
moveToXY(15, 15); // Переместить в точку (15, 15)
delay(2000);
}
6. Частые ошибки
Ошибка 1: Забыли про радианы
// НЕПРАВИЛЬНО:
float theta = 45; // Это градусы!
float x = L * cos(theta); // cos ожидает радианы!
// ПРАВИЛЬНО:
float theta = 45 * PI / 180; // Перевели в радианы
float x = L * cos(theta);
Ошибка 2: Не проверили достижимость
// НЕПРАВИЛЬНО:
float cos_theta2 = ...;
float theta2 = acos(cos_theta2); // Может быть NaN!
// ПРАВИЛЬНО:
if (abs(cos_theta2) > 1) {
Serial.println("Точка недостижима!");
return false;
}
Ошибка 3: Попали в сингулярность
Проблема: Рука полностью вытянута (θ2 = 0°)
Симптом: IK не может решить задачу или даёт странные углы
Решение: Добавить проверку и ограничить углы
7. Для продвинутых: 3D-кинематика
В 3D добавляются:
- Третья координата Z
- Больше углов (обычно 6 для полной свободы)
- Матрицы преобразования (Denavit-Hartenberg)
Для школьных проектов используйте библиотеки:
- Python:
ikpy,roboticstoolbox - ROS 2: MoveIt
- Симуляторы: CoppeliaSim, Gazebo
Проверь себя
✅ Смогу ли я:
- Рассчитать FK для 2D-манипулятора?
- Объяснить, почему IK может иметь несколько решений?
- Написать код для простой IK на Arduino?
- Привести пример, когда у IK нет решения?
Что дальше?
- Степени свободы — сколько осей нужно роботу
- Динамика — силы и моменты при движении
- PID-управление — как точно поворачивать моторы
