====== Электронное приложение к набору «IO.KIT Робот Ампи: Шасси» ======
{{ :kits:io-kit:robot-ampie-chassis:io-kit-robot-ampie-chassis-preview.png?nolink&400 |}}
На этой странице ты найдёшь все нужные материалы для проектов набора [[amp>product/io-kit-robot-ampie-chassis?utm_source=man&utm_campaign=io-kit-robot-ampie-chassis&utm_medium=wiki|Робот Ампи: Шасси]] из серии [[amp>collection/io-kits?utm_source=man&utm_campaign=io-kit-robot-ampie-chassis&utm_medium=wiki|IO.KIT]]:
* Схему подключения модулей.
* Исходный код программ (копируй его в редактор Arduino IDE).
* Дополнительные материалы: программные библиотеки, даташиты и т. п.
**Обрати внимание**
Для сборки и функционирования шасси робота Ампи тебе понадобится [[amp>product/io-kit-basic?utm_source=man&utm_campaign=io-kit-robot-ampie-chassis&utm_medium=wiki|IO.KIT Базовый]]!
===== Схема =====
{{ :kits:io-kit:robot-ampie-chassis:io-kit-robot-chassis-drawing-wiring.png?nolink |}}
===== Проекты =====
Прежде чем приступать к экспериментам, нужно подготовить свой компьютер:
* Установи среду программирования [[https://amperka.ru/page/arduino-ide?utm_source=announce&utm_campaign=io-kit-robot-ampie-chassis&utm_medium=wiki|Arduino IDE]] и копируй туда готовый код проектов.
* Установи [[#библиотеки|дополнительные библиотеки]] для Arduino IDE, пользуясь [[программирование:библиотеки|нашим руководством]].
**Драйвер чипа CH340**
Установи [[articles:driver-ch340|драйвер CH340 для Windows]] или [[projects:installing-the-ch340-on-linux|Linux]], чтобы твой компьютер мог корректно распознать и прошить плату Iskra Nano.
==== №1. Техосмотр ====
Переверни шасси робота Ампи на спину колёсами вверх
и протестируй сервоприводы.
{{ :kits:io-kit:robot-ampie-chassis:010-info.1.png?nolink&600 |}}
// Подключаем библиотеку для работы с сервомоторами
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 100;
// Создаём объекты для работы с левым и правым сервомотором
Servo servoL;
Servo servoR;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Задаём плавно максимальную скорость вперёд
motorsDrive(100, 100);
// Ждём интервал задержки езды
delay(DELAY_DRIVE);
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Ждём интервал задержки остановки
delay(DELAY_STOP);
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
==== №2. Движение волной ====
Запусти движение шасси вперёд и назад с остановками
на отдых.
{{ :kits:io-kit:robot-ampie-chassis:020-info.1.png?nolink |}}
// Подключаем библиотеку для работы с сервомоторами
#include
// Создаём объекты для работы с левым и правым сервомотором
Servo servoL;
Servo servoR;
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 100;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Задаём плавно максимальную скорость вперёд
motorsDrive(100, 100);
// Ждём интервал задержки езды
delay(DELAY_DRIVE);
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Ждём интервал задержки остановки
delay(DELAY_STOP);
// Задаём плавно максимальную скорость назад
motorsDrive(-100, -100);
// Ждём интервал задержки езды
delay(DELAY_DRIVE);
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Ждём интервал задержки остановки
delay(DELAY_STOP);
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
==== №3. Калибровка моторов ====
Научи шасси робота Ампи держать ровный курс.
{{ :kits:io-kit:robot-ampie-chassis:030-info.1.png?nolink |}}
// Подключаем библиотеку для работы с сервомоторами
#include
// Создаём объекты для работы с левым и правым сервомотором
Servo servoL;
Servo servoR;
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константы для калибровки скорости левого и правого мотора
// Определите в какую сторону клонит робота
// Отклонение вправо: левый мотор быстрее правого.
// Увеличивайте константу SPEED_FACTOR_L до тех пор, пока движение не выровняется
// Отклонение влево: правый мотор быстрее левого.
// Увеличивайте константу SPEED_FACTOR_R до тех пор, пока движение не выровняется
constexpr int SPEED_FACTOR_L = 0;
constexpr int SPEED_FACTOR_R = 30;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 30;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Задаём плавно максимальную скорость вперёд
motorsDrive(100, 100);
// Ждём интервал задержки езды
delay(DELAY_DRIVE);
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Ждём интервал задержки остановки
delay(DELAY_STOP);
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Создаём переменные для хранения калибровочных коэффициентов скорости
// левого и правого мотора
int speedFactorL = 0;
int speedFactorR = 0;
// Вычисляем калибровочные коэффициенты для моторов
speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
speedL -= speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
speedL += speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
speedR -= speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
speedR += speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
==== №4. Змейка ====
Запусти движение шасси змейкой с возможностью
настройки траектории.
{{ :kits:io-kit:robot-ampie-chassis:040-info.1.png?nolink |}}
// Подключаем библиотеку для работы с сервомоторами
#include
// Создаём объекты для работы с левым и правым сервомотором
Servo servoL;
Servo servoR;
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константы для калибровки скорости левого и правого мотора
constexpr int SPEED_FACTOR_L = 0;
constexpr int SPEED_FACTOR_R = 30;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 500;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 30;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Задаём на скорости поворот влево
motorsDrive(20, 100);
// Ждём интервал задержки езды
delay(DELAY_DRIVE);
// Задаём на скорости поворот вправо
motorsDrive(100, 20);
// Ждём интервал задержки езды
delay(DELAY_DRIVE);
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Создаём переменные для хранения калибровочных коэффициентов скорости
// левого и правого мотора
int speedFactorL = 0;
int speedFactorR = 0;
// Вычисляем калибровочные коэффициенты для моторов
speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
speedL -= speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
speedL += speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
speedR -= speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
speedR += speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
==== №5. Консольный дальномер ====
Активируй дальномер и считай расстояние до препятствия
в консоль.
{{ :kits:io-kit:robot-ampie-chassis:050-info.2.png?nolink&650 |}}
// Подключаем библиотеку для работы с дальномером
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятные имена пинам 12 и 11 с дальномером
constexpr uint8_t TRIG_PIN = 12;
constexpr uint8_t ECHO_PIN = 11;
// Создаём объект для работы с дальномером
EasyUltrasonic distSensor;
void setup() {
// Открываем монитор Serial-порта
Serial.begin(9600);
// Подключаем дальномер
distSensor.attach(TRIG_PIN, ECHO_PIN);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Считываем расстояние до объекта в см
float distance = distSensor.getDistanceCM();
// Выводим результат в консоль
Serial.print(distance);
Serial.println(" cm");
// Ждём 100 мс
delay(100);
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
==== №6. Часовой ====
Пусть шасси робота Ампи несёт дозор и активирует сирену
при виде постороннего объекта.
{{ :kits:io-kit:robot-ampie-chassis:060-info.1.png?nolink&500 |}}
// Подключаем библиотеку для работы с дальномером
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятные имена пинам 12 и 11 с дальномером
constexpr uint8_t TRIG_PIN = 12;
constexpr uint8_t ECHO_PIN = 11;
// Создаём константы для хранения минимальной и максимальной частоты в Гц
constexpr int MIN_FREQUENCY = 634;
constexpr int MAX_FREQUENCY = 912;
// Создаём константы для задержки ноты и паузы в мс
constexpr int DELAY_NOTE = 7;
constexpr int DELAY_PAUSE = 500;
// Создаём константу для хранения тригера сигнализации в см
constexpr int DISTANCE_ALARM = 10;
// Создаём объект для работы с дальномером
EasyUltrasonic distSensor;
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем дальномер
distSensor.attach(TRIG_PIN, ECHO_PIN);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Считываем расстояние до объекта в см
float distance = distSensor.getDistanceCM();
// Задержка для стабилизации показаний
delay(10);
// Если текущее расстояние до препятствия меньше тригера
if (distance < DISTANCE_ALARM) {
// Включаем звуковую сигнализацию
melodyAlarm();
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
// Функция звуковой сигнализации
void melodyAlarm() {
// Создаём константу для хранения текущей частоты
int frequency;
// Медленно восходящий тон
for (frequency = MIN_FREQUENCY; frequency <= MAX_FREQUENCY; frequency++) {
tone(BUZZER_PIN, frequency);
delay(DELAY_NOTE);
}
// Медленно нисходящий тон
for (frequency = MAX_FREQUENCY; frequency >= MIN_FREQUENCY; frequency--) {
tone(BUZZER_PIN, frequency);
delay(DELAY_NOTE);
}
// Пауза
noTone(BUZZER_PIN);
delay(DELAY_PAUSE);
// Серия быстро восходящих и нисходящих тонов
for (int count = 0; count < 10; count++) {
for (frequency = MIN_FREQUENCY; frequency <= MAX_FREQUENCY; frequency++) {
tone(BUZZER_PIN, frequency);
delayMicroseconds(50);
}
for (frequency = MAX_FREQUENCY; frequency >= MIN_FREQUENCY; frequency--) {
tone(BUZZER_PIN, frequency);
delayMicroseconds(50);
}
}
// Пауза
noTone(BUZZER_PIN);
delay(DELAY_PAUSE);
// Серия повторяющего тона
for (int count = 0; count < 3; count++) {
tone(BUZZER_PIN, (MIN_FREQUENCY + MAX_FREQUENCY) / 6, 300);
delay(DELAY_NOTE * 75);
}
// Пауза
noTone(BUZZER_PIN);
delay(DELAY_PAUSE);
}
==== №7. Препятствие, стоп! ====
Научи шасси робота Ампи останавливаться перед препятствиями.
{{ :kits:io-kit:robot-ampie-chassis:070-info.1.png?nolink |}}
// Подключаем библиотеку для работы с дальномером
#include
// Подключаем библиотеку для работы с сервомоторами
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятные имена пинам 12 и 11 с дальномером
constexpr uint8_t TRIG_PIN = 12;
constexpr uint8_t ECHO_PIN = 11;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константы для калибровки скорости левого и правого мотора
constexpr int SPEED_FACTOR_L = 0;
constexpr int SPEED_FACTOR_R = 30;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 30;
// Создаём константу для хранения базовой частоты
constexpr int FREQUENCY = 2000;
// Создаём константы для хранения минимальной и максимальной частоты
constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
// Создаём константу для хранения тригера сигнализации в см
constexpr int DISTANCE_DETOUR = 20;
// Создаём объект для работы с дальномером
EasyUltrasonic distSensor;
// Создаём объект для работы с сервомоторами
Servo servoL;
Servo servoR;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем дальномер
distSensor.attach(TRIG_PIN, ECHO_PIN);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Передаём случайное число с пина A1
// для последующей генерации случайных чисел
randomSeed(analogRead(A1));
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Задаём максимальную скорость вперёд
motorsDrive(100, 100, false);
// Считываем расстояние до объекта в см
float distance = distSensor.getDistanceCM();
// Задержка для стабилизации показаний с дальномера
delay(10);
// Если текущее расстояние до препятствия меньше тригера
if (distance < DISTANCE_DETOUR) {
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Запускаем мелодию R2-D2
melodyR2D2();
// Замораживаем программу
while (1)
;
}
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Создаём переменные для хранения калибровочных коэффициентов скорости
// левого и правого мотора
int speedFactorL = 0;
int speedFactorR = 0;
// Вычисляем калибровочные коэффициенты для моторов
speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
speedL -= speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
speedL += speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
speedR -= speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
speedR += speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
// Функция мелодии R2-D2
void melodyR2D2() {
// Вызываем функцию генератора последовательных длинных семплов
toneLongSamples();
// Вызываем функцию генератора непоследовательных коротких семплов
toneShortSamples();
}
// Функция генерации последовательных длинных семплов
void toneLongSamples() {
// Генерируем случайное количество семплов от 1 до 6
int countSamples = random(1, 7);
// Перебираем нумерацию семплов в цикле
for (int i = 0; i < countSamples; i++) {
// Генерируем случайное число: true или false
bool typeSamples = random(0, 2);
// Если тип семпла true
if (typeSamples) {
// Вызываем функцию генерации тона toneSlowDownFastUp:
// Сначала медленный убывающий тон со случайными задержками
// Затем быстрый возрастающий тон со случайными задержками
toneSlowDownFastUp();
} else {
// Если тип семпла false
// Вызываем функцию генерации тона toneSlowUpFastDown:
// Сначала медленный возрастающий тон со случайными задержками
// Затем быстрый убывающий тон со случайными задержками
toneSlowUpFastDown();
}
}
}
// Функция генерации непоследовательных коротких семплов
void toneShortSamples() {
// Генерируем случайное количество семплов от 3 до 9
int countSamples = random(3, 10);
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
for (int i = 0; i <= countSamples; i++) {
// Генерируем случайный интервал на базе FREQUENCY
int range = random(-FREQUENCY, FREQUENCY);
tone(BUZZER_PIN, frequency + range);
// Выполняем случайную задержку от 70 до 170 мс
delay(random(70, 170));
// Выключаем звук
noTone(BUZZER_PIN);
// Выполняем случайную задержку от 0 до 30 мс
delay(random(0, 30));
}
}
// Функция генерации звуковой последовательности
// Сначала медленный убывающий тон со случайными задержками
// Затем быстрый возрастающий тон со случайными задержками
void toneSlowDownFastUp() {
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
// Генерируем медленный понижающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 2));
delayMicroseconds(random(0, 1000));
}
// Генерируем быстрый повышающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, frequency + (range * 10));
delayMicroseconds(random(0, 1000));
}
}
// Функция генерации звуковой последовательности
// Сначала медленный возрастающий тон со случайными задержками
// Затем быстрый убывающий тон со случайными задержками
void toneSlowUpFastDown() {
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
// Генерируем медленный возрастающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 2));
delayMicroseconds(random(0, 1000));
}
// Генерируем быстрый понижающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 10));
delayMicroseconds(random(0, 1000));
}
}
==== №8. Препятствие, поворот, поехали! ====
Научи шасси робота Ампи по-умному огибать препятствия.
{{ :kits:io-kit:robot-ampie-chassis:080-info.1.png?nolink&600 |}}
// Подключаем библиотеку для работы с дальномером
#include
// Подключаем библиотеку для работы с сервомоторами
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятные имена пинам 12 и 11 с дальномером
constexpr uint8_t TRIG_PIN = 12;
constexpr uint8_t ECHO_PIN = 11;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константы для калибровки скорости левого и правого мотора
constexpr int SPEED_FACTOR_L = 0;
constexpr int SPEED_FACTOR_R = 30;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 30;
// Создаём константу для хранения базовой частоты
constexpr int FREQUENCY = 2000;
// Создаём константы для хранения минимальной и максимальной частоты
constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
// Создаём константу для хранения тригера сигнализации в см
constexpr int DISTANCE_DETOUR = 20;
// Создаём объект для работы с дальномером
EasyUltrasonic distSensor;
// Создаём объект для работы с сервомоторами
Servo servoL;
Servo servoR;
// Создаём перечисление состояний робота с соответствующей переменной
enum {
ROBOT_DRIVE, // Робот едет вперёд
ROBOT_DETECT_DETOUR, // Робот зафиксировал препятствие
} robotState;
// Создаём перечисление направления движения робота с соответствующей переменной
enum DirectionDetours {
LEFT,
RIGHT,
} direction;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем дальномер
distSensor.attach(TRIG_PIN, ECHO_PIN);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Передаём случайное число с пина A1
// для последующей генерации случайных чисел
randomSeed(analogRead(A1));
// Включаем стартовую мелодию
melodyStart();
// Устанавливаем режим «Робот едет вперёд»
robotState = ROBOT_DRIVE;
}
void loop() {
// Если установлен режим «Робот едет вперёд»
if (robotState == ROBOT_DRIVE) {
// Переходим в функцию обработки режима «Робот едет вперёд»
handleRobotDrive();
}
// Если установлен режим «Робот зафиксировал препятствие»
if (robotState == ROBOT_DETECT_DETOUR) {
// Переходим в функцию обработки режима «Робот зафиксировал препятствие»
handleRobotDetectDetour();
}
}
// Функция обработки режима «Робот едет вперёд»
void handleRobotDrive() {
// Задаём максимальную скорость вперёд
motorsDrive(100, 100, false);
// Считываем расстояние до объекта в см
float distance = distSensor.getDistanceCM();
// Задержка для стабилизации показаний с дальномера
delay(10);
// Если текущее расстояние до препятствия меньше тригера
if (distance < DISTANCE_DETOUR) {
// Устанавливаем режим «Робот зафиксировал препятствие»
robotState = ROBOT_DETECT_DETOUR;
}
}
// Функция обработки режима «Робот зафиксировал препятствие»
void handleRobotDetectDetour() {
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Запускаем мелодию R2-D2
melodyR2D2();
// Ждём 1 сек
delay(1000);
// Объезжаем препятствие слева 500 мс
motorsDetourBarrier(LEFT, 500);
// Устанавливаем режим «Робот едет вперёд»
robotState = ROBOT_DRIVE;
}
// Функция объезда препятствие
void motorsDetourBarrier(DirectionDetours direction, int delayDrive) {
// Выбираем направления заднего хода для разворота
if (direction == LEFT) {
motorsDrive(-50, 0, false);
} else if (direction == RIGHT) {
motorsDrive(0, -50, false);
}
// Ждём интервал задержки езды
delay(delayDrive);
// Останавливаем сервомоторы с плавным торможением
motorsDrive(0, 0);
// Ждём интервал задержки остановки
delay(1000);
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Создаём переменные для хранения калибровочных коэффициентов скорости
// левого и правого мотора
int speedFactorL = 0;
int speedFactorR = 0;
// Вычисляем калибровочные коэффициенты для моторов
speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
speedL -= speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
speedL += speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
speedR -= speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
speedR += speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
// Функция мелодии R2-D2
void melodyR2D2() {
// Вызываем функцию генератора последовательных длинных семплов
toneLongSamples();
// Вызываем функцию генератора непоследовательных коротких семплов
toneShortSamples();
}
// Функция генерации последовательных длинных семплов
void toneLongSamples() {
// Генерируем случайное количество семплов от 1 до 6
int countSamples = random(1, 7);
// Перебираем нумерацию семплов в цикле
for (int i = 0; i < countSamples; i++) {
// Генерируем случайное число: true или false
bool typeSamples = random(0, 2);
// Если тип семпла true
if (typeSamples) {
// Вызываем функцию генерации тона toneSlowDownFastUp:
// Сначала медленный убывающий тон со случайными задержками
// Затем быстрый возрастающий тон со случайными задержками
toneSlowDownFastUp();
} else {
// Если тип семпла false
// Вызываем функцию генерации тона toneSlowUpFastDown:
// Сначала медленный возрастающий тон со случайными задержками
// Затем быстрый убывающий тон со случайными задержками
toneSlowUpFastDown();
}
}
}
// Функция генерации непоследовательных коротких семплов
void toneShortSamples() {
// Генерируем случайное количество семплов от 3 до 9
int countSamples = random(3, 10);
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
for (int i = 0; i <= countSamples; i++) {
// Генерируем случайный интервал на базе FREQUENCY
int range = random(-FREQUENCY, FREQUENCY);
tone(BUZZER_PIN, frequency + range);
// Выполняем случайную задержку от 70 до 170 мс
delay(random(70, 170));
// Выключаем звук
noTone(BUZZER_PIN);
// Выполняем случайную задержку от 0 до 30 мс
delay(random(0, 30));
}
}
// Функция генерации звуковой последовательности
// Сначала медленный убывающий тон со случайными задержками
// Затем быстрый возрастающий тон со случайными задержками
void toneSlowDownFastUp() {
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
// Генерируем медленный понижающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 2));
delayMicroseconds(random(0, 1000));
}
// Генерируем быстрый повышающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, frequency + (range * 10));
delayMicroseconds(random(0, 1000));
}
}
// Функция генерации звуковой последовательности
// Сначала медленный возрастающий тон со случайными задержками
// Затем быстрый убывающий тон со случайными задержками
void toneSlowUpFastDown() {
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
// Генерируем медленный возрастающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 2));
delayMicroseconds(random(0, 1000));
}
// Генерируем быстрый понижающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 10));
delayMicroseconds(random(0, 1000));
}
}
==== №9. Трусливый бот ====
Пусть шасси робота Ампи убегает прочь от приближающихся
объектов.
{{ :kits:io-kit:robot-ampie-chassis:090-info.1.png?nolink |}}
// Подключаем библиотеку для работы с дальномером
#include
// Подключаем библиотеку для работы с сервомоторами
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятные имена пинам 12 и 11 с дальномером
constexpr uint8_t TRIG_PIN = 12;
constexpr uint8_t ECHO_PIN = 11;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константы для калибровки скорости левого и правого мотора
constexpr int SPEED_FACTOR_L = 0;
constexpr int SPEED_FACTOR_R = 30;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 30;
// Создаём константу для хранения базовой частоты
constexpr int FREQUENCY = 2000;
// Создаём константы для хранения минимальной и максимальной частоты
constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
// Создаём константу для хранения тригера сигнализации в см
constexpr int DISTANCE_DETOUR = 20;
// Создаём объект для работы с дальномером
EasyUltrasonic distSensor;
// Создаём объект для работы с сервомоторами
Servo servoL;
Servo servoR;
// Создаём перечисление состояний робота с соответствующей переменной
enum {
ROBOT_STANDING, // Робот стоит на месте
ROBOT_STANDING_DETECT_DETOUR, // Робот стоял на месте и зафиксировал препятствие
ROBOT_DRIVE, // Робот едет вперёд
ROBOT_DRIVE_DETECT_DETOUR, // Робот ехал вперёд и зафиксировал препятствие
} robotState;
// Создаём перечисление направления движения робота с соответствующей переменной
enum DirectionDetours {
LEFT,
RIGHT,
} direction;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем дальномер
distSensor.attach(TRIG_PIN, ECHO_PIN);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Передаём случайное число с пина A1
// для последующей генерации случайных чисел
randomSeed(analogRead(A1));
// Включаем стартовую мелодию
melodyStart();
// Устанавливаем режим «Робот стоит на месте»
robotState = ROBOT_STANDING;
}
void loop() {
// Если установлен режим «Робот стоит на месте»
if (robotState == ROBOT_STANDING) {
// Переходим в функцию обработки режима «Робот стоит на месте»
handleRobotStanding();
}
// Если установлен режим «Робот стоял на месте и зафиксировал препятствие»
if (robotState == ROBOT_STANDING_DETECT_DETOUR) {
// Переходим в функцию обработки режима «Робот стоял на месте и зафиксировал препятствие»
handleRobotStandingDetectDetour();
}
// Если установлен режим «Робот едет вперёд»
if (robotState == ROBOT_DRIVE) {
// Переходим в функцию обработки режима «Робот едет вперёд»
handleRobotDrive();
}
// Если установлен режим «Робот ехал вперёд и зафиксировал препятствие»
if (robotState == ROBOT_DRIVE_DETECT_DETOUR) {
// Переходим в функцию обработки режима «Робот ехал вперёд и зафиксировал препятствие»
handleRobotDriveDetectDetour();
}
}
// Функция обработки режима «Робот стоит на месте»
void handleRobotStanding() {
// Считываем расстояние до объекта в см
float distance = distSensor.getDistanceCM();
// Задержка для стабилизации показаний с дальномера
delay(10);
// Если текущее расстояние до препятствия меньше тригера
if (distance < DISTANCE_DETOUR) {
// Устанавливаем режим «Робот стоял на месте и зафиксировал препятствие»
robotState = ROBOT_STANDING_DETECT_DETOUR;
}
}
// Функция обработки режима «Робот стоял на месте и зафиксировал препятствие»
void handleRobotStandingDetectDetour() {
// Запускаем мелодию R2-D2
melodyR2D2();
// Ждём 1 сек
delay(1000);
// Объезжаем препятствие слева 1000 мс
motorsDetourBarrier(LEFT, 1000);
// Устанавливаем режим «Робот едет вперёд»
robotState = ROBOT_DRIVE;
}
// Функция обработки режима «Робот едет вперёд»
void handleRobotDrive() {
// Задаём максимальную скорость вперёд
motorsDrive(100, 100, false);
// Считываем расстояние до объекта в см
float dist = distSensor.getDistanceCM();
// Задержка для стабилизации показаний с дальномера
delay(10);
// Если текущее расстояние до препятствия меньше тригера
if (dist < DISTANCE_DETOUR) {
// Устанавливаем режим «Робот зафиксировал препятствие»
robotState = ROBOT_DRIVE_DETECT_DETOUR;
}
}
// Функция обработки режима «Робот зафиксировал препятствие»
void handleRobotDriveDetectDetour() {
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Запускаем мелодию R2-D2
melodyR2D2();
// Ждём 1 сек
delay(1000);
// Объезжаем препятствие слева 500 мс
motorsDetourBarrier(LEFT, 500);
// Устанавливаем режим «Робот едет вперёд»
robotState = ROBOT_DRIVE;
}
// Функция объезда препятствие
void motorsDetourBarrier(DirectionDetours direction, int delayDrive) {
// Выбираем направления заднего хода для разворота
if (direction == LEFT) {
motorsDrive(-50, 0, false);
} else if (direction == RIGHT) {
motorsDrive(0, -50, false);
}
// Ждём интервал задержки езды
delay(delayDrive);
// Останавливаем плавно сервомоторы
motorsDrive(0, 0);
// Ждём интервал задержки остановки
delay(1000);
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Создаём переменные для хранения калибровочных коэффициентов скорости
// левого и правого мотора
int speedFactorL = 0;
int speedFactorR = 0;
// Вычисляем калибровочные коэффициенты для моторов
speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
speedL -= speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
speedL += speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
speedR -= speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
speedR += speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
// Функция мелодии R2-D2
void melodyR2D2() {
// Вызываем функцию генератора последовательных длинных семплов
toneLongSamples();
// Вызываем функцию генератора непоследовательных коротких семплов
toneShortSamples();
}
// Функция генерации последовательных длинных семплов
void toneLongSamples() {
// Генерируем случайное количество семплов от 1 до 6
int countSamples = random(1, 7);
// Перебираем нумерацию семплов в цикле
for (int i = 0; i < countSamples; i++) {
// Генерируем случайное число: true или false
bool typeSamples = random(0, 2);
// Если тип семпла true
if (typeSamples) {
// Вызываем функцию генерации тона toneSlowDownFastUp:
// Сначала медленный убывающий тон со случайными задержками
// Затем быстрый возрастающий тон со случайными задержками
toneSlowDownFastUp();
} else {
// Если тип семпла false
// Вызываем функцию генерации тона toneSlowUpFastDown:
// Сначала медленный возрастающий тон со случайными задержками
// Затем быстрый убывающий тон со случайными задержками
toneSlowUpFastDown();
}
}
}
// Функция генерации непоследовательных коротких семплов
void toneShortSamples() {
// Генерируем случайное количество семплов от 3 до 9
int countSamples = random(3, 10);
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
for (int i = 0; i <= countSamples; i++) {
// Генерируем случайный интервал на базе FREQUENCY
int range = random(-FREQUENCY, FREQUENCY);
tone(BUZZER_PIN, frequency + range);
// Выполняем случайную задержку от 70 до 170 мс
delay(random(70, 170));
// Выключаем звук
noTone(BUZZER_PIN);
// Выполняем случайную задержку от 0 до 30 мс
delay(random(0, 30));
}
}
// Функция генерации звуковой последовательности
// Сначала медленный убывающий тон со случайными задержками
// Затем быстрый возрастающий тон со случайными задержками
void toneSlowDownFastUp() {
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
// Генерируем медленный понижающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 2));
delayMicroseconds(random(0, 1000));
}
// Генерируем быстрый повышающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, frequency + (range * 10));
delayMicroseconds(random(0, 1000));
}
}
// Функция генерации звуковой последовательности
// Сначала медленный возрастающий тон со случайными задержками
// Затем быстрый убывающий тон со случайными задержками
void toneSlowUpFastDown() {
// Генерируем случайную частоту на базе FREQUENCY
int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
// Генерируем медленный возрастающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 2));
delayMicroseconds(random(0, 1000));
}
// Генерируем быстрый понижающий тон со случайными задержками
for (int range = 0; range <= random(100, 1000); range++) {
tone(BUZZER_PIN, (range * 10));
delayMicroseconds(random(0, 1000));
}
}
==== №10. Следопыт ====
Сделай из робота Ампи настоящего сыщика: пусть он пресле-
дует замеченные дальномером объекты.
{{ :kits:io-kit:robot-ampie-chassis:100-info.1.png?nolink |}}
// Подключаем библиотеку для работы с дальномером
#include
// Подключаем библиотеку для работы с сервомоторами
#include
// Даём понятное имя пину 3 с пищалкой
constexpr uint8_t BUZZER_PIN = 3;
// Даём понятные имена пинам 12 и 11 с дальномером
constexpr uint8_t TRIG_PIN = 12;
constexpr uint8_t ECHO_PIN = 11;
// Даём понятное имя пину 7 с левым сервомотором
constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
// Даём понятное имя пину 10 с правым сервомотором
constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
// Задаём максимально доступную скорость сервомоторов
// в сырых значениях по часовой и против часовой стрелки
constexpr int SPEED_RAW_MAX_CW = 30;
constexpr int SPEED_RAW_MAX_CCW = 150;
// Вычисляем показатель остановки сервомоторов в сырых значениях
constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
// Создаём константы для калибровки скорости левого и правого мотора
constexpr int SPEED_FACTOR_L = 0;
constexpr int SPEED_FACTOR_R = 30;
// Создаём константу задержки езды
constexpr int DELAY_DRIVE = 3000;
// Создаём константу задержки остановки
constexpr int DELAY_STOP = 1000;
// Создаём константу задержки плавной остановки
constexpr int DELAY_SMOOTH = 30;
// Создаём константу для желаемого расстояние зоны поиска объекта в см
constexpr int DISTANCE_RANGE = 100;
// Создаём константу для желаемого расстояние до объекта в см
constexpr int DISTANCE_TARGET = 30;
// Создаём константы для хранения желаемой зоны до объекта
constexpr int MIN_DISTANCE_TARGET = DISTANCE_TARGET - (0.25 * DISTANCE_TARGET);
constexpr int MAX_DISTANCE_TARGET = DISTANCE_TARGET + (0.25 * DISTANCE_TARGET);
// Создаём объект для работы с дальномером
EasyUltrasonic distSensor;
// Создаём объект для работы с сервомоторами
Servo servoL;
Servo servoR;
// Прототип функции управления моторами
void motorsDrive(int speedL, int speedR, bool smooth = true);
void setup() {
// Настраиваем пин с пищалкой в режим выхода
pinMode(BUZZER_PIN, OUTPUT);
// Подключаем дальномер
distSensor.attach(TRIG_PIN, ECHO_PIN);
// Подключаем сервомоторы
servoL.attach(SERVO_WHEEL_L_PIN);
servoR.attach(SERVO_WHEEL_R_PIN);
// Останавливаем сервомоторы
motorsDrive(0, 0, false);
// Включаем стартовую мелодию
melodyStart();
}
void loop() {
// Считываем расстояние до объекта в см
float distance = distSensor.getDistanceCM();
// Задержка для стабилизации показаний с дальномера
delay(10);
// Проверяем расстояние до объекта
if (distance > DISTANCE_RANGE) {
// Если в зоне поиска робота нет объектов, стоим
motorsDrive(0, 0);
} else if (distance < MIN_DISTANCE_TARGET) {
// Если робот слишком близко к цели, едем назад
motorsDrive(-50, -50);
} else if (distance > MIN_DISTANCE_TARGET && distance < MAX_DISTANCE_TARGET) {
// Если робот в зоне слежения цели, стоим
motorsDrive(0, 0);
} else if (distance > MAX_DISTANCE_TARGET) {
// Если робот далеко от цели, едем вперёд
motorsDrive(50, 50);
}
}
// Функция управления сервомоторами
void motorsDrive(int speedL, int speedR, bool smooth) {
// Создаём переменные для хранения текущей скорости
// левого и правого мотора в сырых значениях
int speedRawL = 0;
int speedRawR = 0;
// Создаём переменные для хранения обновлённой скорости
// левого и правого мотора в сырых значениях
int newSpeedRawL = 0;
int newSpeedRawR = 0;
// Создаём переменные для хранения калибровочных коэффициентов скорости
// левого и правого мотора
int speedFactorL = 0;
int speedFactorR = 0;
// Вычисляем калибровочные коэффициенты для моторов
speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
// Получаем текущие показания моторов в сырых значениях
speedRawL = servoL.read();
speedRawR = servoR.read();
// Преобразуем показания скорости левого мотора
if (speedL == 0) {
newSpeedRawL = SPEED_RAW_STOP;
} else if (speedL > 0) {
speedL -= speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
} else if (speedL < 0) {
speedL += speedFactorL;
newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
}
// Преобразуем показания скорости правого мотора
if (speedR == 0) {
newSpeedRawR = SPEED_RAW_STOP;
} else if (speedR > 0) {
speedR -= speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
} else if (speedR < 0) {
speedR += speedFactorR;
newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
}
// Проверяем состояние флага: плавное или мгновенное изменение скорости
if (smooth) {
// Плавное изменение скорости
int steps = 10;
for (int i = 0; i <= steps; i++) {
int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
servoL.write(newSpeedRawSmoothL);
servoR.write(newSpeedRawSmoothR);
delay(DELAY_SMOOTH);
}
} else {
// Мгновенное изменение скорости
servoL.write(newSpeedRawL);
servoR.write(newSpeedRawR);
}
}
// Функция стартовой мелодии
void melodyStart() {
tone(BUZZER_PIN, 300, 500);
delay(1000);
tone(BUZZER_PIN, 400, 500);
delay(1000);
tone(BUZZER_PIN, 500, 500);
delay(1000);
tone(BUZZER_PIN, 700, 300);
delay(1000);
}
===== Ресурсы =====
* [[amp>collection/io-kits?utm_source=man&utm_campaign=io-kit-robot-ampie-chassis&utm_medium=wiki|Наборы IO.KIT]] в магазине
* [[kits:io-kit|Электронные материалы IO.KIT]]
==== Софт ====
* [[amp>page/arduino-ide?utm_source=announce&utm_campaign=io-kit-robot-ampie-chassis&utm_medium=wiki|Страница загрузки Arduino IDE]]
==== Библиотеки ====
* [[https://github.com/end2endzone/AnyRtttl|AnyRtttl]]
* [[https://github.com/SpulberGeorge/EasyUltrasonic|EasyUltrasonic]]
* [[https://github.com/Arduino-IRremote/Arduino-IRremote|IRremote]]
* [[https://www.arduino.cc/reference/en/libraries/servo/|Servo]]