2.2. Всенаправленные колеса.md
В предыдущем параграфе мы научились управлять обычными коллекторными двигателями. Но если вы посмотрите на робота из набора AQROBO.PRO, то заметите, что его колёса выглядят очень необычно. Это не простые колёса, а колёса Mecanum — гениальное изобретение, которое дарит роботу невероятную свободу передвижения.
Проблема обычных колёс
Представьте себе обычный автомобиль. Чтобы припарковаться у тротуара, водителю приходится выполнять несколько манёвров вперёд-назад. Он не может просто взять и поехать боком. Обычные колёса могут эффективно двигаться только в двух направлениях: вперёд и назад. Любое другое движение требует поворота.
Колёса Mecanum решают эту проблему. Робот, оснащённый ими, может двигаться в любом направлении — вперёд, назад, боком, по диагонали — и даже вращаться на месте, не меняя своей ориентации в пространстве. В мире компьютерных игр такой манёвр называется «стрейф» (strafe).
Секрет колёс Mecanum
Вся магия колёс Mecanum заключается в их конструкции. Вокруг основного обода колеса установлены небольшие ролики, причём расположены они строго под углом 45 градусов к основной оси вращения колеса.
Когда такое колесо начинает вращаться, из-за этих наклонных роликов сила, которую оно создаёт, раскладывается на две составляющие:
- Одна толкает робота вперёд или назад (вдоль оси колеса).
- Другая толкает робота вбок (перпендикулярно оси колеса).
Управляя направлением вращения каждого из четырёх колёс по отдельности, мы можем комбинировать эти силы, заставляя ненужные векторы сил гасить друг друга, а нужные — складываться.
Управление роботом
Чтобы заставить робота двигаться в нужном направлении, нам нужно подать правильные команды на каждый из четырёх моторов. Давайте разберём основные комбинации.
- Движение вперёд/назад. Всё просто. Все четыре колеса вращаются в одном направлении, как у обычного автомобиля.
- Движение вбок (стрейф). Здесь начинается магия. Чтобы поехать вправо, колёса по одной диагонали (переднее левое и заднее правое) должны вращаться вперёд, а колёса по другой диагонали (переднее правое и заднее левое) — назад. В этом случае продольные составляющие сил гасят друг друга, а боковые — складываются, толкая всего робота вправо.
- Вращение на месте. Колёса с левой стороны вращаются в одну сторону, а с правой — в противоположную.
Вот сводная таблица команд для каждого из четырёх моторов (ПЛ - передний левый, ПП - передний правый, ЗЛ - задний левый, ЗП - задний правый):
| Движение | Мотор ПЛ | Мотор ПП | Мотор ЗЛ | Мотор ЗП |
|---|---|---|---|---|
| Вперёд | Вперёд | Вперёд | Вперёд | Вперёд |
| Назад | Назад | Назад | Назад | Назад |
| Вправо (стрейф) | Вперёд | Назад | Назад | Вперёд |
| Влево (стрейф) | Назад | Вперёд | Вперёд | Назад |
| Вращение по часовой | Вперёд | Назад | Вперёд | Назад |
| Вращение против часовой | Назад | Вперёд | Назад | Вперёд |
Зачем это нужно?
Колёса Mecanum обеспечивают высочайшую манёвренность. Эта технология незаменима там, где пространство ограничено. Вы можете встретить такие колёса:
- На складских роботах (например, на складах Amazon), которые должны быстро и точно перемещаться между стеллажами.
- На погрузчиках и другой спецтехнике, работающей в узких проходах.
- На соревновательных роботах (например, в RoboCup), где манёвренность даёт огромное преимущество.
- На некоторых современных инвалидных креслах, позволяя пользователю легко маневрировать в квартире.
Отлично! Практическая часть с кодом — это то, что нужно после теории. Я подготовил фрагмент, который логично вписывается после раздела «Зачем это нужно?». Он содержит схему подключения для двух моторов и программу, реализующую все основные движения робота с колёсами Mecanum. Код написан в виде простых и понятных функций, как в вашем примере.
Подключение и программная реализация
Для управления четырьмя моторами нам понадобится два драйвера L9110S и восемь GPIO пинов Рудирона. Четыре из них должны поддерживать ШИМ для управления скоростью.
Программа управления Давайте напишем программу, которая будет содержать функции для каждого базового движения. Это позволит нам в будущем легко комбинировать их для создания сложного поведения.
// --- Пины для левой стороны ---
const int leftFrontDirPin = 13;
const int leftFrontSpeedPin = 12;
const int leftBackDirPin = 11;
const int leftBackSpeedPin = 8;
// --- Пины для правой стороны ---
const int rightFrontDirPin = A0;
const int rightFrontSpeedPin = 20;
const int rightBackDirPin = A1;
const int rightBackSpeedPin = A2;
void setup() {
// Настраиваем все пины на выход
pinMode(leftFrontDirPin, OUTPUT);
pinMode(leftFrontSpeedPin, OUTPUT);
pinMode(leftBackDirPin, OUTPUT);
pinMode(leftBackSpeedPin, OUTPUT);
pinMode(rightFrontDirPin, OUTPUT);
pinMode(rightFrontSpeedPin, OUTPUT);
pinMode(rightBackDirPin, OUTPUT);
pinMode(rightBackSpeedPin, OUTPUT);
}
// --- Функции для управления отдельными моторами ---
// dir=0 - вперёд, dir=1 - назад
void runMotor(int dirPin, int speedPin, int dir, int speed) {
digitalWrite(dirPin, dir);
analogWrite(speedPin, speed);
}
// --- Функции для базовых движений ---
void forward(int speed) {
runMotor(leftFrontDirPin, leftFrontSpeedPin, 0, speed);
runMotor(leftBackDirPin, leftBackSpeedPin, 0, speed);
runMotor(rightFrontDirPin, rightFrontSpeedPin, 0, speed);
runMotor(rightBackDirPin, rightBackSpeedPin, 0, speed);
}
void backward(int speed) {
runMotor(leftFrontDirPin, leftFrontSpeedPin, 1, speed);
runMotor(leftBackDirPin, leftBackSpeedPin, 1, speed);
runMotor(rightFrontDirPin, rightFrontSpeedPin, 1, speed);
runMotor(rightBackDirPin, rightBackSpeedPin, 1, speed);
}
void strafeLeft(int speed) {
runMotor(leftFrontDirPin, leftFrontSpeedPin, 1, speed);
runMotor(leftBackDirPin, leftBackSpeedPin, 0, speed);
runMotor(rightFrontDirPin, rightFrontSpeedPin, 0, speed);
runMotor(rightBackDirPin, rightBackSpeedPin, 1, speed);
}
void strafeRight(int speed) {
runMotor(leftFrontDirPin, leftFrontSpeedPin, 0, speed);
runMotor(leftBackDirPin, leftBackSpeedPin, 1, speed);
runMotor(rightFrontDirPin, rightFrontSpeedPin, 1, speed);
runMotor(rightBackDirPin, rightBackSpeedPin, 0, speed);
}
void rotateClockwise(int speed) {
runMotor(leftFrontDirPin, leftFrontSpeedPin, 0, speed);
runMotor(leftBackDirPin, leftBackSpeedPin, 0, speed);
runMotor(rightFrontDirPin, rightFrontSpeedPin, 1, speed);
runMotor(rightBackDirPin, rightBackSpeedPin, 1, speed);
}
void stopMotors() {
runMotor(leftFrontDirPin, leftFrontSpeedPin, 0, 0);
runMotor(leftBackDirPin, leftBackSpeedPin, 0, 0);
runMotor(rightFrontDirPin, rightFrontSpeedPin, 0, 0);
runMotor(rightBackDirPin, rightBackSpeedPin, 0, 0);
}
// --- Основная программа: демонстрация движений ---
void loop() {
int moveSpeed = 200; // Установим среднюю скорость (0-255)
// Едем вперёд 2 секунды
forward(moveSpeed);
delay(2000);
stopMotors();
delay(1000);
// Едем боком вправо 2 секунды
strafeRight(moveSpeed);
delay(2000);
stopMotors();
delay(1000);
// Вращаемся на месте по часовой стрелке 1 секунду
rotateClockwise(moveSpeed);
delay(1000);
stopMotors();
delay(1000);
}