3.11.md
ДВИЖЕНИЕ ПО ТРАЕКТОРИИ
РОБОТЕЛЕЖКА — это простейшая платформа на колесах. Два колеса ведущих (закреплены на валах двигателей) и одно пассивное с возможность поворота на 360 градусов.
Двигатели используются для перемещения:
- Вперед
- Назад
- Поворота на произвольный угол
НАПОМИНАНИЕ При использовании внешнего питания сначала подключаем внешнее питание, а потом USB-кабель для связи или программирования. При выключении все делаем наоборот: сначала вытаскиваем USB-кабель, а затем внешнее питание. Несоблюдение данного правила может привести к выходу из строя платы Рудирон.
Для поворота налево достаточно работы одного правого двигателя. вращение правого колеса повернет роботележку влево. Вращение только левого колеса повернет роботележку вправо. Угол поворота будет зависеть от того на какой угол повернулось колесо. Грубо можно сказать, что угол поворота зависит от времени вращения колеса. Схема подключения у нас остается той же, что и в предыдущем уроке. Для повторения приведем данную схему и здесь.
Подача питания на мотор:
1 Питание от контроллера. Не рекомендуется так как может выйти из строя стабилизатор питания контроллера! Хотя это маловероятно, так как на плате установлен самовосстанавливающийся предохранитель, но все же не стоит рисковать.
2 Питание мотора от внешнего источника. Рекомендуемый вариант подключения. Для управления двигателем необходимо задать направление вращения двигателя и скорость вращения.
Составим алгоритм работы тележки, чтобы она ехала по квадрату:
Алгоритм включает событие, задающее старт движения тележке. Если после включения питания тележка сразу начнет пытаться ехать по квадрату, то нам будет некомфортно с ней работать. Лучше сделать начало движение роботележки по нажатию кнопки. Тогда мы можем подключить питание, поставить тележку на поверхность. Убедившись, что есть пространство для движения нажать на кнопку.
Сам алгоритм движения прост. Двигаемся некоторое время прямо. Останавливаемся и поворачиваемся на 90 градусов вправо. Затем все повторяется еще 3 раза.
Для составления полного алгоритма необходимо сначала представить алгоритм поворота роботележки через управление двигателями.
Представление полного алгоритма займет много места. Мы знаем как реализовать каждый блок общего алгоритма. Поэтому перейдем сразу к написанию программы. За основу возьмем программу движения вперед и ее модифицируем.
Скопируем папку проекта с движением по линии sketch_robo_line с новым именем sketch_robo_square в туже директорию.
Открываем проект в Visual Studio Code. Обязательно удаляем папку build и сохраняем файл CmakesLists.txt.
Текст программы движения по квадрату:
#include “Arduino.h”
#include “drive.h”
void setup()
{
pinMode(BUTTON_BUILTIN_1, INPUT_PULLDOWN);
drive_init(); // вызываем функцию из drive.cpp по начальной настройке двигателей - движение вперед и нулевая скорость
}
bool btnState; // создаем переменную для хранения состояния нажатия кнопки true или false
void loop()
{
btnState = digitalRead(BUTTON_BUILTIN_1);
if (btnState) // нажата ли кнопка
{
// двигаемся вперед 5 секунд
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для
движения вперед на средней скорости
right_motor(DIRECTION_FORWD,70); // включаем правый двигатель для движения вперед на средней скорости
delay(3000);
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000); // поворачиваем направо вращая левое колесо в течении секунды
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на средней скорости
delay(1000); // даем колесу крутиться секунду
// останавливаем двигатели
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на средней скорости
delay(1000); // даем колесу крутиться секунду
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000);
// повторяем действия описанные выше еще 3 раза
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,70); // включаем правый двигатель для движения вперед на средней скорости
delay(3000);
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000);
// поворачиваем направо вращая левое колесо в течении секунды
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на средней скорости
delay(1000); // даем колесу крутиться секунду
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000);
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,70); // включаем правый двигатель для движения вперед на средней скорости
delay(3000);
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000);
// поворачиваем направо вращая левое колесо в течении секунды
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на средней скорости
delay(1000); // даем колесу крутиться секунду
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000);
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,70); // включаем правый двигатель для движения вперед на средней скорости
delay(3000);
// останавливаем двигатели
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
delay(1000)
}
}
Файлы drive.h и drive.cpp мы не изменяли. Изменения коснулись исключительно основного файла программы sketch.cpp. По нажатию кнопки на контроллере мы последовательно устанавливаем режимы работы двигателей в соответствии с необходимым режимом перемещения роботележки.
Режимы перемещения тележки:
1 Остановка – оба двигателя должны иметь нулевую скорость вращени.
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель для движения вперед на малой скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на малой скорости
2 Прямолинейное движение – оба двигателя вращаются в одну строну и с одинаковой скоростью.
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,70); // включаем правый двигатель для движения вперед на средней скорости
3 Поворот направо – правый двигатель не вращается, а левый вращается вперед. время паузы на исполнении действий тележкой
lefr_motor(DIRECTION_FORWD,70); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель для движения вперед на средней скорости
Обратите внимание, что при движении вперед и повороте на 90 градусов мы задаем временную задержку. При прямолинейном движении время задержки повлияет на расстояние, которое проедет тележка. Во время поворота вредя задержки повлияет на угол поворота тележки.
Угол поворота будет зависеть от скорости вращения колеса, его диаметра и подбирается экспериментально. Так же подбирается время для прохождения необходимого линейного расстояния.
Как мы видим тест программы уже стал длинным и неудобным в случае необходимости внесения изменений. Так как у нас есть уже понимание, какие режимы работы тележку существуют, то давайте опишем их в отдельных функциях и внесем изменения в нашу программу:
- Остановка — stop_telegka(int time_sleep);
- Прямолинейное расстояние — forward_telegka(int speed, int time_sleep);
- Поворот — rotation_telegka(int direction, int speed, int time_sleep);
Внесем в файл программы drive.cpp и drive.h три новых функции.
Передаваемый параметры:
- speed — скорость вращения двигателей,
- direction — направление поворота (1- право, 0 - лево),
- time_sleep — время паузы на исполнении действий тележкой.
Вносим изменения в заголовочный файл drive.h, где объявляем три функции и дополнительно две константы для задания направления поворота тележки:
#define LEFT_ROTATION 0 // константа поворота налево
#define RIGHT_ROTATION 1 // константа поворота направо
void stop_telegka(int time_sleep); // остановка тележки
void forward_telegka(int speed, int time_sleep); // движение вперед
void rotation_telegka(int direction, int speed, int time_sleep); // поворот тележки
Полный текст файла drive.h :
#define DIRECTION_FORWD true // направление движения вперед
#define DIRECTION_BACK false // направление движение назад
#define DIR_LEFT 4 // направление вращения левого двигателя
#define SPEED_LEFT 7 // скорость вращения левого двигателя
#define DIR_RIGHT 6 // направление вращения правого двигателя
#define SPEED_RIGHT 8 // скорость вращения левого двигателя
#define LEFT_ROTATION 0 // константа поворота налево
#define RIGHT_ROTATION 1 // константа поворота направо
void drive_setup (); // функция настройки портов контроллера для управления двигателями
void drive_init (); // функция начального управления двигателями - установка нулевой скорости и вращения вперед
void lefr_motor (bool direction,int speed); // функция установки скорости и направления вращения левого двигателя
void right_motor (bool driection,int speed); // функция установки скорости и направления вращения правого двигателя
void stop_telegka(int time_sleep); // остановка тележки
void forward_telegka(int speed, int time_sleep); // движение вперед
void rotation_telegka(int direction, int speed, int time_sleep); // поворот тележки
Описываем реализацию работы новых функций в файле drive.cpp:
void stop_telegka(int time_sleep) // остановка тележки
{
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель
delay(time_sleep);
}
void forward_telegka(int speed, int time_sleep) // движение вперед
{
lefr_motor(DIRECTION_FORWD,speed); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,speed); // включаем правый двигатель для движения вперед на средней скорости
delay(time_sleep);
}
void rotation_telegka(int direction, int speed, int time_sleep) // поворот тележки
{
if (direction == 0)
{
lefr_motor(DIRECTION_FORWD,speed); // включаем левый двигатель для движения вперед на средней скорости
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель
delay(time_sleep);
}
else {
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель
right_motor(DIRECTION_FORWD,speed); // включаем правый двигатель для движения вперед на средней скорости
delay(time_sleep);
}
}
Все функции простые в реализации. В функции rotation_telegka мы проводим проверку в какую сторону происходит поворот тележки. Это мы сделали для создания универсальной функции на все случаи жизни.
Полный текст drive.cpp:
#include “Arduino.h”
#include «drive.h»
void drive_setup () // функция настройки портов контроллера для управления двигателями
{
pinMode(DIR_LEFT, OUTPUT); pinMode(SPEED_LEFT, OUTPUT);
pinMode(DIR_RIGHT, OUTPUT); pinMode(SPEED_RIGHT, OUTPUT);
}
void drive_init () // функция начального управления двигателями - установка нулевой скорости и вращения вперед
{
drive_setup();
lefr_motor(DIRECTION_FORWD,0); // устанавливаем направление вращения - вперед
right_motor(DIRECTION_FORWD,0); // устанавливаем нулевую скорость вращения двигателя
}
// функция установки скорости и направления вращения левого двигателя
void lefr_motor (bool direction,int speed)
{
digitalWrite(DIR_LEFT, direction); // задаем направление вращения двигателя
analogWrite(SPEED_LEFT, speed); // задаем скорость вращения в виде сигнала шим
}
// функция установки скорости и направления вращения правого двигателя
void right_motor (bool directiont,int speed)
{
digitalWrite(DIR_RIGHT, directiont); // задаем направление вращения двигателя
analogWrite(SPEED_RIGHT, speed); // задаем скорость вращения в виде сигнала шим
}
void stop_telegka(int time_sleep) // остановка тележки
{
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель
delay(time_sleep);
}
void forward_telegka(int speed, int time_sleep) // движение вперед
{
lefr_motor(DIRECTION_FORWD,speed); // включаем левый двигатель для движения вперед
right_motor(DIRECTION_FORWD,speed); // включаем правый двигатель для движения вперед
delay(time_sleep);
}
void rotation_telegka(int direction, int speed, int time_sleep) // поворот тележки
{
if (direction == 1)
{
lefr_motor(DIRECTION_FORWD,speed); // включаем левый двигатель для движения вперед
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель
delay(time_sleep);
}
else {
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель
right_motor(DIRECTION_FORWD,speed); // включаем правый двигатель для движения вперед
delay(time_sleep);
}
}
Заменим в основном фале проекта sketch.cpp вызов команд на управление отдельными двигателями нашими функциями:
void rotation_telegka(int direction, int speed, int time_sleep) // поворот тележки
{
if (direction == 1)
{
lefr_motor(DIRECTION_FORWD,speed); // включаем левый двигатель для движения вперед
right_motor(DIRECTION_FORWD,0); // выключаем правый двигатель
delay(time_sleep);
}
else {
lefr_motor(DIRECTION_FORWD,0); // выключаем левый двигатель
right_motor(DIRECTION_FORWD,speed); // включаем правый двигатель для движения вперед
delay(time_sleep);
}
}
Заменим в основном фале проекта sketch.cpp вызов команд на управление отдельными двигателями нашими функциями:
#include “Arduino.h”
#include “drive.h”
void setup()
{
pinMode(BUTTON_BUILTIN_1, INPUT_PULLDOWN);
drive_init(); // вызываем функцию из drive.cpp по начальной настройке двигателей - движение вперед и нулевая скорость
}
bool btnState; // создаем переменную для хранения состояния нажатия кнопки true или false
void loop()
{
stop_telegka(10); // останавливаем тележку
btnState = digitalRead(BUTTON_BUILTIN_1);
if (btnState) // нажата ли кнопка
{
forward_telegka(70,3000); // двигаемся вперед 3 секунды на средней скорости 70 макс 255.
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
rotation_telegka(RIGHT_ROTATION,70,1000); //поворачиваем вправо на скорости 55 в течении 2 секунд
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
forward_telegka(70,3000); // двигаемся вперед 3 секунды на средней скорости 70 макс 255.
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
rotation_telegka(RIGHT_ROTATION,70,1000); //поворачиваем вправо на скорости 55 в течении 2 секунд
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
forward_telegka(70,3000); // двигаемся вперед 3 секунды на средней скорости 155 макс 255.
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
rotation_telegka(RIGHT_ROTATION,70,1000); //поворачиваем вправо на скорости 70 в течении 1 секунды
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
forward_telegka(70,3000); // двигаемся вперед 3 секунды на средней скорости 70 макс 255.
stop_telegka(500); // останавливаем тележку с паузой 0.5 секунды
rotation_telegka(RIGHT_ROTATION,70,1000); //поворачиваем вправо на скорости 70 в течении 1 секунды
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
}
}
Наша программа стала меньше и лучше читается. Большой набор команд по управлению отдельными двигателями мы заменили осознанными функциями движения. Поэтому легко читается логика работы программы и перемещение роботележки.
Упростим текст программы еще раз, зная, что у нас идет последовательное четырехкратное выполнение последовательности:
forward_telegka(70,3000); // двигаемся вперед 3 секунды на средней скорости 70 макс 255.
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
rotation_telegka(RIGHT_ROTATION,70,1000); //поворачиваем вправо на скорости 70 в течении 1 секунды
stop_telegka(1000); // останавливаем тележку с пайзой 1 секунды
Если, что-то повторяется подряд больше 2 раз нужно создать цикл:
#include “Arduino.h”
#include “drive.h”
void setup()
{
pinMode(BUTTON_BUILTIN_1, INPUT_PULLDOWN);
drive_init(); // вызываем функцию из drive.cpp по начальной настройке
двигателей - движение вперед и нулевая скорость
}
bool btnState; // создаем переменную для хранения состояния нажатия кнопки true или false
void loop()
{
stop_telegka(10); // останавливаем тележку
btnState = digitalRead(BUTTON_BUILTIN_1);
if (btnState) // нажата ли кнопка
{
for(int i = 0; i<4; i++)
{
forward_telegka(70,3000); // двигаемся вперед 3 секунды на средней скорости 70 макс 255.
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
rotation_telegka(RIGHT_ROTATION,70,1000); //поворачиваем вправо на скорости 70 в течении 1 секунд
stop_telegka(1000); // останавливаем тележку с паузой 1 секунды
}
}
}
Теперь текст программы очень компактный, так как мы сделали две важные вещи:
- код управления отдельными двигателями сгруппировали в режимы перемещения тележки и оформили в виде функций
- повторяющийся код использовали в цикле
Использование цикла позволяет, меняя количество повторений заставить тележку двигаться по 6-8-10-12 отрезкам пути, рисуя шестигранники, восьмигранники и т д. Загружаем скомпилированный файл в контроллер, переключаем джампер питания на внешний источник питания, устанавливаем джампер на исполнение программы и наблюдаем результат работы программы – тележка едет по квадрату! Если квадрат не получается, то необходимо подобрать время задержек при поворотах или скорость поворота. Не забываем для начала движения нажимать встроенную кнопку B1.
ПРИМЕЧАНИЕ Если Вы хотите выполнять программу при последующих включениях «Рудирона», то не забудьте переставить перемычку из положения «Режим программирования» обратно в «Режим выполнения». Если этого не сделать, то программа при включении «Рудирона» выполняться не будет.
ВЫВОДЫ
Мы научились программировать движение тележки по траектории, поняли принципы выполнения поворотов, научились дополнять собственную библиотеку новыми функциями.
СПИСОК КОНТРОЛЬНЫХ ВОПРОСОВ
- С какими целями новые функции управления добавляются в отдельную библиотеку, а не в основную программу?
- Какие новые функции мы разработали? Их назначение?
- Что необходимо для осуществления поворота направо?
- Что необходимо для осуществления поворота налево?
- Будет ли совершать движение роботележка, если мы не напишем код, отвечающий за обработку нажатия кнопки?
- Для чего мы в начале работы программы анализируем нажатие кнопки?
- Что надо исправить для выполнения точного поворота на 90?
- Что нам дает использование цикла в основной части программы?
- Можно было бы не писать отдельно функции из п.2? И какой результат был в этом случае?
- Что будет результатом выполнения программы?
СПИСОК ДОПОЛНИТЕЛЬНЫХ ЗАДАЧ
- Использовать для написания программы среду Arduino IDE.
- Написать программу движения по прямоугольнику.
- Написать программу движения по прямоугольнику в противоположную сторону
ЭЛЕМЕНТЫ КОНТРОЛЯ И ПРОВЕДЕНИЯ СОРЕВНОВАНИЙ
Проведение тестирования по контрольным вопросам. Критерии: кто быстрее и допустил меньшее количество ошибок.
Написание одного из трех вариантов (исходный и два варианта из списка дополнительных задач) программы и загрузка этого варианта в контроллер. Критерии: Правильно написанная программа согласно выданного задания, работающий контроллер и наименьшее количество времени затраченного на эти работы.
- время паузы на исполнении действий тележкой