Инструменты пользователя

Инструменты сайта


Электронное приложение к набору «IO.KIT Робот Ампи: Шасси»

На этой странице ты найдёшь все нужные материалы для проектов набора Робот Ампи: Шасси из серии IO.KIT:

  • Схему подключения модулей.
  • Исходный код программ (копируй его в редактор Arduino IDE).
  • Дополнительные материалы: программные библиотеки, даташиты и т. п.

Обрати внимание

Для сборки и функционирования шасси робота Ампи тебе понадобится IO.KIT Базовый!

Схема

Проекты

Прежде чем приступать к экспериментам, нужно подготовить свой компьютер:

Драйвер чипа CH340

Установи драйвер CH340 для Windows или Linux, чтобы твой компьютер мог корректно распознать и прошить плату Iskra Nano.

№1. Техосмотр

Переверни шасси робота Ампи на спину колёсами вверх и протестируй сервоприводы.

Testing.ino
  1. // Подключаем библиотеку для работы с сервомоторами
  2. #include <Servo.h>
  3.  
  4. // Даём понятное имя пину 3 с пищалкой
  5. constexpr uint8_t BUZZER_PIN = 3;
  6.  
  7. // Даём понятное имя пину 7 с левым сервомотором
  8. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  9.  
  10. // Даём понятное имя пину 10 с правым сервомотором
  11. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  12.  
  13. // Задаём максимально доступную скорость сервомоторов
  14. // в сырых значениях по часовой и против часовой стрелки
  15. constexpr int SPEED_RAW_MAX_CW = 30;
  16. constexpr int SPEED_RAW_MAX_CCW = 150;
  17.  
  18. // Вычисляем показатель остановки сервомоторов в сырых значениях
  19. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  20.  
  21. // Создаём константу задержки езды
  22. constexpr int DELAY_DRIVE = 3000;
  23. // Создаём константу задержки остановки
  24. constexpr int DELAY_STOP = 1000;
  25. // Создаём константу задержки плавной остановки
  26. constexpr int DELAY_SMOOTH = 100;
  27.  
  28. // Создаём объекты для работы с левым и правым сервомотором
  29. Servo servoL;
  30. Servo servoR;
  31.  
  32. // Прототип функции управления моторами
  33. void motorsDrive(int speedL, int speedR, bool smooth = true);
  34.  
  35. void setup() {
  36. // Настраиваем пин с пищалкой в режим выхода
  37. pinMode(BUZZER_PIN, OUTPUT);
  38. // Подключаем сервомоторы
  39. servoL.attach(SERVO_WHEEL_L_PIN);
  40. servoR.attach(SERVO_WHEEL_R_PIN);
  41. // Останавливаем сервомоторы
  42. motorsDrive(0, 0, false);
  43. // Включаем стартовую мелодию
  44. melodyStart();
  45. }
  46.  
  47. void loop() {
  48. // Задаём плавно максимальную скорость вперёд
  49. motorsDrive(100, 100);
  50. // Ждём интервал задержки езды
  51. delay(DELAY_DRIVE);
  52. // Останавливаем плавно сервомоторы
  53. motorsDrive(0, 0);
  54. // Ждём интервал задержки остановки
  55. delay(DELAY_STOP);
  56. }
  57.  
  58. // Функция управления сервомоторами
  59. void motorsDrive(int speedL, int speedR, bool smooth) {
  60. // Создаём переменные для хранения текущей скорости
  61. // левого и правого мотора в сырых значениях
  62. int speedRawL = 0;
  63. int speedRawR = 0;
  64. // Создаём переменные для хранения обновлённой скорости
  65. // левого и правого мотора в сырых значениях
  66. int newSpeedRawL = 0;
  67. int newSpeedRawR = 0;
  68.  
  69. // Получаем текущие показания моторов в сырых значениях
  70. speedRawL = servoL.read();
  71. speedRawR = servoR.read();
  72.  
  73. // Преобразуем показания скорости левого мотора
  74. if (speedL == 0) {
  75. newSpeedRawL = SPEED_RAW_STOP;
  76. } else if (speedL > 0) {
  77. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  78. } else if (speedL < 0) {
  79. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  80. }
  81.  
  82. // Преобразуем показания скорости правого мотора
  83. if (speedR == 0) {
  84. newSpeedRawR = SPEED_RAW_STOP;
  85. } else if (speedR > 0) {
  86. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  87. } else if (speedR < 0) {
  88. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  89. }
  90.  
  91. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  92. if (smooth) {
  93. // Плавное изменение скорости
  94. int steps = 10;
  95. for (int i = 0; i <= steps; i++) {
  96. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  97. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  98. servoL.write(newSpeedRawSmoothL);
  99. servoR.write(newSpeedRawSmoothR);
  100. delay(DELAY_SMOOTH);
  101. }
  102. } else {
  103. // Мгновенное изменение скорости
  104. servoL.write(newSpeedRawL);
  105. servoR.write(newSpeedRawR);
  106. }
  107. }
  108.  
  109. // Функция стартовой мелодии
  110. void melodyStart() {
  111. tone(BUZZER_PIN, 300, 500);
  112. delay(1000);
  113. tone(BUZZER_PIN, 400, 500);
  114. delay(1000);
  115. tone(BUZZER_PIN, 500, 500);
  116. delay(1000);
  117. tone(BUZZER_PIN, 700, 300);
  118. delay(1000);
  119. }

№2. Движение волной

Запусти движение шасси вперёд и назад с остановками на отдых.

Drive.ino
  1. // Подключаем библиотеку для работы с сервомоторами
  2. #include <Servo.h>
  3.  
  4. // Создаём объекты для работы с левым и правым сервомотором
  5. Servo servoL;
  6. Servo servoR;
  7.  
  8. // Даём понятное имя пину 3 с пищалкой
  9. constexpr uint8_t BUZZER_PIN = 3;
  10.  
  11. // Даём понятное имя пину 7 с левым сервомотором
  12. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  13.  
  14. // Даём понятное имя пину 10 с правым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  16.  
  17. // Задаём максимально доступную скорость сервомоторов
  18. // в сырых значениях по часовой и против часовой стрелки
  19. constexpr int SPEED_RAW_MAX_CW = 30;
  20. constexpr int SPEED_RAW_MAX_CCW = 150;
  21.  
  22. // Вычисляем показатель остановки сервомоторов в сырых значениях
  23. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  24.  
  25. // Создаём константу задержки езды
  26. constexpr int DELAY_DRIVE = 3000;
  27. // Создаём константу задержки остановки
  28. constexpr int DELAY_STOP = 1000;
  29. // Создаём константу задержки плавной остановки
  30. constexpr int DELAY_SMOOTH = 100;
  31.  
  32. // Прототип функции управления моторами
  33. void motorsDrive(int speedL, int speedR, bool smooth = true);
  34.  
  35. void setup() {
  36. // Настраиваем пин с пищалкой в режим выхода
  37. pinMode(BUZZER_PIN, OUTPUT);
  38. // Подключаем сервомоторы
  39. servoL.attach(SERVO_WHEEL_L_PIN);
  40. servoR.attach(SERVO_WHEEL_R_PIN);
  41. // Останавливаем сервомоторы
  42. motorsDrive(0, 0, false);
  43. // Включаем стартовую мелодию
  44. melodyStart();
  45. }
  46.  
  47. void loop() {
  48. // Задаём плавно максимальную скорость вперёд
  49. motorsDrive(100, 100);
  50. // Ждём интервал задержки езды
  51. delay(DELAY_DRIVE);
  52. // Останавливаем плавно сервомоторы
  53. motorsDrive(0, 0);
  54. // Ждём интервал задержки остановки
  55. delay(DELAY_STOP);
  56. // Задаём плавно максимальную скорость назад
  57. motorsDrive(-100, -100);
  58. // Ждём интервал задержки езды
  59. delay(DELAY_DRIVE);
  60. // Останавливаем плавно сервомоторы
  61. motorsDrive(0, 0);
  62. // Ждём интервал задержки остановки
  63. delay(DELAY_STOP);
  64. }
  65.  
  66. // Функция управления сервомоторами
  67. void motorsDrive(int speedL, int speedR, bool smooth) {
  68. // Создаём переменные для хранения текущей скорости
  69. // левого и правого мотора в сырых значениях
  70. int speedRawL = 0;
  71. int speedRawR = 0;
  72. // Создаём переменные для хранения обновлённой скорости
  73. // левого и правого мотора в сырых значениях
  74. int newSpeedRawL = 0;
  75. int newSpeedRawR = 0;
  76.  
  77. // Получаем текущие показания моторов в сырых значениях
  78. speedRawL = servoL.read();
  79. speedRawR = servoR.read();
  80.  
  81. // Преобразуем показания скорости левого мотора
  82. if (speedL == 0) {
  83. newSpeedRawL = SPEED_RAW_STOP;
  84. } else if (speedL > 0) {
  85. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  86. } else if (speedL < 0) {
  87. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  88. }
  89.  
  90. // Преобразуем показания скорости правого мотора
  91. if (speedR == 0) {
  92. newSpeedRawR = SPEED_RAW_STOP;
  93. } else if (speedR > 0) {
  94. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  95. } else if (speedR < 0) {
  96. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  97. }
  98.  
  99. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  100. if (smooth) {
  101. // Плавное изменение скорости
  102. int steps = 10;
  103. for (int i = 0; i <= steps; i++) {
  104. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  105. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  106. servoL.write(newSpeedRawSmoothL);
  107. servoR.write(newSpeedRawSmoothR);
  108. delay(DELAY_SMOOTH);
  109. }
  110. } else {
  111. // Мгновенное изменение скорости
  112. servoL.write(newSpeedRawL);
  113. servoR.write(newSpeedRawR);
  114. }
  115. }
  116.  
  117. // Функция стартовой мелодии
  118. void melodyStart() {
  119. tone(BUZZER_PIN, 300, 500);
  120. delay(1000);
  121. tone(BUZZER_PIN, 400, 500);
  122. delay(1000);
  123. tone(BUZZER_PIN, 500, 500);
  124. delay(1000);
  125. tone(BUZZER_PIN, 700, 300);
  126. delay(1000);
  127. }

№3. Калибровка моторов

Научи шасси робота Ампи держать ровный курс.

DriveCalibration.ino
  1. // Подключаем библиотеку для работы с сервомоторами
  2. #include <Servo.h>
  3.  
  4. // Создаём объекты для работы с левым и правым сервомотором
  5. Servo servoL;
  6. Servo servoR;
  7.  
  8. // Даём понятное имя пину 3 с пищалкой
  9. constexpr uint8_t BUZZER_PIN = 3;
  10.  
  11. // Даём понятное имя пину 7 с левым сервомотором
  12. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  13.  
  14. // Даём понятное имя пину 10 с правым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  16.  
  17. // Задаём максимально доступную скорость сервомоторов
  18. // в сырых значениях по часовой и против часовой стрелки
  19. constexpr int SPEED_RAW_MAX_CW = 30;
  20. constexpr int SPEED_RAW_MAX_CCW = 150;
  21.  
  22. // Вычисляем показатель остановки сервомоторов в сырых значениях
  23. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  24.  
  25. // Создаём константы для калибровки скорости левого и правого мотора
  26. // Определите в какую сторону клонит робота
  27. // Отклонение вправо: левый мотор быстрее правого.
  28. // Увеличивайте константу SPEED_FACTOR_L до тех пор, пока движение не выровняется
  29. // Отклонение влево: правый мотор быстрее левого.
  30. // Увеличивайте константу SPEED_FACTOR_R до тех пор, пока движение не выровняется
  31. constexpr int SPEED_FACTOR_L = 0;
  32. constexpr int SPEED_FACTOR_R = 30;
  33.  
  34. // Создаём константу задержки езды
  35. constexpr int DELAY_DRIVE = 3000;
  36. // Создаём константу задержки остановки
  37. constexpr int DELAY_STOP = 1000;
  38. // Создаём константу задержки плавной остановки
  39. constexpr int DELAY_SMOOTH = 30;
  40.  
  41. // Прототип функции управления моторами
  42. void motorsDrive(int speedL, int speedR, bool smooth = true);
  43.  
  44. void setup() {
  45. // Настраиваем пин с пищалкой в режим выхода
  46. pinMode(BUZZER_PIN, OUTPUT);
  47. // Подключаем сервомоторы
  48. servoL.attach(SERVO_WHEEL_L_PIN);
  49. servoR.attach(SERVO_WHEEL_R_PIN);
  50. // Останавливаем сервомоторы
  51. motorsDrive(0, 0, false);
  52. // Включаем стартовую мелодию
  53. melodyStart();
  54. }
  55.  
  56. void loop() {
  57. // Задаём плавно максимальную скорость вперёд
  58. motorsDrive(100, 100);
  59. // Ждём интервал задержки езды
  60. delay(DELAY_DRIVE);
  61. // Останавливаем плавно сервомоторы
  62. motorsDrive(0, 0);
  63. // Ждём интервал задержки остановки
  64. delay(DELAY_STOP);
  65. }
  66.  
  67. // Функция управления сервомоторами
  68. void motorsDrive(int speedL, int speedR, bool smooth) {
  69. // Создаём переменные для хранения текущей скорости
  70. // левого и правого мотора в сырых значениях
  71. int speedRawL = 0;
  72. int speedRawR = 0;
  73. // Создаём переменные для хранения обновлённой скорости
  74. // левого и правого мотора в сырых значениях
  75. int newSpeedRawL = 0;
  76. int newSpeedRawR = 0;
  77.  
  78. // Создаём переменные для хранения калибровочных коэффициентов скорости
  79. // левого и правого мотора
  80. int speedFactorL = 0;
  81. int speedFactorR = 0;
  82.  
  83. // Вычисляем калибровочные коэффициенты для моторов
  84. speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
  85. speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
  86.  
  87. // Получаем текущие показания моторов в сырых значениях
  88. speedRawL = servoL.read();
  89. speedRawR = servoR.read();
  90.  
  91. // Преобразуем показания скорости левого мотора
  92. if (speedL == 0) {
  93. newSpeedRawL = SPEED_RAW_STOP;
  94. } else if (speedL > 0) {
  95. speedL -= speedFactorL;
  96. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  97. } else if (speedL < 0) {
  98. speedL += speedFactorL;
  99. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  100. }
  101.  
  102. // Преобразуем показания скорости правого мотора
  103. if (speedR == 0) {
  104. newSpeedRawR = SPEED_RAW_STOP;
  105. } else if (speedR > 0) {
  106. speedR -= speedFactorR;
  107. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  108. } else if (speedR < 0) {
  109. speedR += speedFactorR;
  110. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  111. }
  112.  
  113. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  114. if (smooth) {
  115. // Плавное изменение скорости
  116. int steps = 10;
  117. for (int i = 0; i <= steps; i++) {
  118. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  119. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  120. servoL.write(newSpeedRawSmoothL);
  121. servoR.write(newSpeedRawSmoothR);
  122. delay(DELAY_SMOOTH);
  123. }
  124. } else {
  125. // Мгновенное изменение скорости
  126. servoL.write(newSpeedRawL);
  127. servoR.write(newSpeedRawR);
  128. }
  129. }
  130.  
  131. // Функция стартовой мелодии
  132. void melodyStart() {
  133. tone(BUZZER_PIN, 300, 500);
  134. delay(1000);
  135. tone(BUZZER_PIN, 400, 500);
  136. delay(1000);
  137. tone(BUZZER_PIN, 500, 500);
  138. delay(1000);
  139. tone(BUZZER_PIN, 700, 300);
  140. delay(1000);
  141. }

№4. Змейка

Запусти движение шасси змейкой с возможностью настройки траектории.

Snake.ino
  1. // Подключаем библиотеку для работы с сервомоторами
  2. #include <Servo.h>
  3.  
  4. // Создаём объекты для работы с левым и правым сервомотором
  5. Servo servoL;
  6. Servo servoR;
  7.  
  8. // Даём понятное имя пину 3 с пищалкой
  9. constexpr uint8_t BUZZER_PIN = 3;
  10.  
  11. // Даём понятное имя пину 7 с левым сервомотором
  12. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  13.  
  14. // Даём понятное имя пину 10 с правым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  16.  
  17. // Задаём максимально доступную скорость сервомоторов
  18. // в сырых значениях по часовой и против часовой стрелки
  19. constexpr int SPEED_RAW_MAX_CW = 30;
  20. constexpr int SPEED_RAW_MAX_CCW = 150;
  21.  
  22. // Вычисляем показатель остановки сервомоторов в сырых значениях
  23. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  24.  
  25. // Создаём константы для калибровки скорости левого и правого мотора
  26. constexpr int SPEED_FACTOR_L = 0;
  27. constexpr int SPEED_FACTOR_R = 30;
  28.  
  29. // Создаём константу задержки езды
  30. constexpr int DELAY_DRIVE = 500;
  31. // Создаём константу задержки остановки
  32. constexpr int DELAY_STOP = 1000;
  33. // Создаём константу задержки плавной остановки
  34. constexpr int DELAY_SMOOTH = 30;
  35.  
  36. // Прототип функции управления моторами
  37. void motorsDrive(int speedL, int speedR, bool smooth = true);
  38.  
  39. void setup() {
  40. // Настраиваем пин с пищалкой в режим выхода
  41. pinMode(BUZZER_PIN, OUTPUT);
  42. // Подключаем сервомоторы
  43. servoL.attach(SERVO_WHEEL_L_PIN);
  44. servoR.attach(SERVO_WHEEL_R_PIN);
  45. // Останавливаем сервомоторы
  46. motorsDrive(0, 0, false);
  47. // Включаем стартовую мелодию
  48. melodyStart();
  49. }
  50.  
  51. void loop() {
  52. // Задаём на скорости поворот влево
  53. motorsDrive(20, 100);
  54. // Ждём интервал задержки езды
  55. delay(DELAY_DRIVE);
  56. // Задаём на скорости поворот вправо
  57. motorsDrive(100, 20);
  58. // Ждём интервал задержки езды
  59. delay(DELAY_DRIVE);
  60. }
  61.  
  62. // Функция управления сервомоторами
  63. void motorsDrive(int speedL, int speedR, bool smooth) {
  64. // Создаём переменные для хранения текущей скорости
  65. // левого и правого мотора в сырых значениях
  66. int speedRawL = 0;
  67. int speedRawR = 0;
  68. // Создаём переменные для хранения обновлённой скорости
  69. // левого и правого мотора в сырых значениях
  70. int newSpeedRawL = 0;
  71. int newSpeedRawR = 0;
  72.  
  73. // Создаём переменные для хранения калибровочных коэффициентов скорости
  74. // левого и правого мотора
  75. int speedFactorL = 0;
  76. int speedFactorR = 0;
  77.  
  78. // Вычисляем калибровочные коэффициенты для моторов
  79. speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
  80. speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
  81.  
  82. // Получаем текущие показания моторов в сырых значениях
  83. speedRawL = servoL.read();
  84. speedRawR = servoR.read();
  85.  
  86. // Преобразуем показания скорости левого мотора
  87. if (speedL == 0) {
  88. newSpeedRawL = SPEED_RAW_STOP;
  89. } else if (speedL > 0) {
  90. speedL -= speedFactorL;
  91. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  92. } else if (speedL < 0) {
  93. speedL += speedFactorL;
  94. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  95. }
  96.  
  97. // Преобразуем показания скорости правого мотора
  98. if (speedR == 0) {
  99. newSpeedRawR = SPEED_RAW_STOP;
  100. } else if (speedR > 0) {
  101. speedR -= speedFactorR;
  102. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  103. } else if (speedR < 0) {
  104. speedR += speedFactorR;
  105. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  106. }
  107.  
  108. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  109. if (smooth) {
  110. // Плавное изменение скорости
  111. int steps = 10;
  112. for (int i = 0; i <= steps; i++) {
  113. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  114. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  115. servoL.write(newSpeedRawSmoothL);
  116. servoR.write(newSpeedRawSmoothR);
  117. delay(DELAY_SMOOTH);
  118. }
  119. } else {
  120. // Мгновенное изменение скорости
  121. servoL.write(newSpeedRawL);
  122. servoR.write(newSpeedRawR);
  123. }
  124. }
  125.  
  126. // Функция стартовой мелодии
  127. void melodyStart() {
  128. tone(BUZZER_PIN, 300, 500);
  129. delay(1000);
  130. tone(BUZZER_PIN, 400, 500);
  131. delay(1000);
  132. tone(BUZZER_PIN, 500, 500);
  133. delay(1000);
  134. tone(BUZZER_PIN, 700, 300);
  135. delay(1000);
  136. }

№5. Консольный дальномер

Активируй дальномер и считай расстояние до препятствия в консоль.

LidarConsole.ino
  1. // Подключаем библиотеку для работы с дальномером
  2. #include <EasyUltrasonic.h>
  3.  
  4. // Даём понятное имя пину 3 с пищалкой
  5. constexpr uint8_t BUZZER_PIN = 3;
  6.  
  7. // Даём понятные имена пинам 12 и 11 с дальномером
  8. constexpr uint8_t TRIG_PIN = 12;
  9. constexpr uint8_t ECHO_PIN = 11;
  10.  
  11. // Создаём объект для работы с дальномером
  12. EasyUltrasonic distSensor;
  13.  
  14. void setup() {
  15. // Открываем монитор Serial-порта
  16. Serial.begin(9600);
  17. // Подключаем дальномер
  18. distSensor.attach(TRIG_PIN, ECHO_PIN);
  19. // Включаем стартовую мелодию
  20. melodyStart();
  21. }
  22.  
  23. void loop() {
  24. // Считываем расстояние до объекта в см
  25. float distance = distSensor.getDistanceCM();
  26. // Выводим результат в консоль
  27. Serial.print(distance);
  28. Serial.println(" cm");
  29. // Ждём 100 мс
  30. delay(100);
  31. }
  32.  
  33. // Функция стартовой мелодии
  34. void melodyStart() {
  35. tone(BUZZER_PIN, 300, 500);
  36. delay(1000);
  37. tone(BUZZER_PIN, 400, 500);
  38. delay(1000);
  39. tone(BUZZER_PIN, 500, 500);
  40. delay(1000);
  41. tone(BUZZER_PIN, 700, 300);
  42. delay(1000);
  43. }

№6. Часовой

Пусть шасси робота Ампи несёт дозор и активирует сирену при виде постороннего объекта.

Security.ino
  1. // Подключаем библиотеку для работы с дальномером
  2. #include <EasyUltrasonic.h>
  3.  
  4. // Даём понятное имя пину 3 с пищалкой
  5. constexpr uint8_t BUZZER_PIN = 3;
  6.  
  7. // Даём понятные имена пинам 12 и 11 с дальномером
  8. constexpr uint8_t TRIG_PIN = 12;
  9. constexpr uint8_t ECHO_PIN = 11;
  10.  
  11. // Создаём константы для хранения минимальной и максимальной частоты в Гц
  12. constexpr int MIN_FREQUENCY = 634;
  13. constexpr int MAX_FREQUENCY = 912;
  14.  
  15. // Создаём константы для задержки ноты и паузы в мс
  16. constexpr int DELAY_NOTE = 7;
  17. constexpr int DELAY_PAUSE = 500;
  18.  
  19. // Создаём константу для хранения тригера сигнализации в см
  20. constexpr int DISTANCE_ALARM = 10;
  21.  
  22. // Создаём объект для работы с дальномером
  23. EasyUltrasonic distSensor;
  24.  
  25. void setup() {
  26. // Настраиваем пин с пищалкой в режим выхода
  27. pinMode(BUZZER_PIN, OUTPUT);
  28. // Подключаем дальномер
  29. distSensor.attach(TRIG_PIN, ECHO_PIN);
  30. // Включаем стартовую мелодию
  31. melodyStart();
  32. }
  33.  
  34. void loop() {
  35. // Считываем расстояние до объекта в см
  36. float distance = distSensor.getDistanceCM();
  37. // Задержка для стабилизации показаний
  38. delay(10);
  39. // Если текущее расстояние до препятствия меньше тригера
  40. if (distance < DISTANCE_ALARM) {
  41. // Включаем звуковую сигнализацию
  42. melodyAlarm();
  43. }
  44. }
  45.  
  46. // Функция стартовой мелодии
  47. void melodyStart() {
  48. tone(BUZZER_PIN, 300, 500);
  49. delay(1000);
  50. tone(BUZZER_PIN, 400, 500);
  51. delay(1000);
  52. tone(BUZZER_PIN, 500, 500);
  53. delay(1000);
  54. tone(BUZZER_PIN, 700, 300);
  55. delay(1000);
  56. }
  57.  
  58. // Функция звуковой сигнализации
  59. void melodyAlarm() {
  60. // Создаём константу для хранения текущей частоты
  61. int frequency;
  62. // Медленно восходящий тон
  63. for (frequency = MIN_FREQUENCY; frequency <= MAX_FREQUENCY; frequency++) {
  64. tone(BUZZER_PIN, frequency);
  65. delay(DELAY_NOTE);
  66. }
  67. // Медленно нисходящий тон
  68. for (frequency = MAX_FREQUENCY; frequency >= MIN_FREQUENCY; frequency--) {
  69. tone(BUZZER_PIN, frequency);
  70. delay(DELAY_NOTE);
  71. }
  72. // Пауза
  73. noTone(BUZZER_PIN);
  74. delay(DELAY_PAUSE);
  75. // Серия быстро восходящих и нисходящих тонов
  76. for (int count = 0; count < 10; count++) {
  77. for (frequency = MIN_FREQUENCY; frequency <= MAX_FREQUENCY; frequency++) {
  78. tone(BUZZER_PIN, frequency);
  79. delayMicroseconds(50);
  80. }
  81. for (frequency = MAX_FREQUENCY; frequency >= MIN_FREQUENCY; frequency--) {
  82. tone(BUZZER_PIN, frequency);
  83. delayMicroseconds(50);
  84. }
  85. }
  86. // Пауза
  87. noTone(BUZZER_PIN);
  88. delay(DELAY_PAUSE);
  89. // Серия повторяющего тона
  90. for (int count = 0; count < 3; count++) {
  91. tone(BUZZER_PIN, (MIN_FREQUENCY + MAX_FREQUENCY) / 6, 300);
  92. delay(DELAY_NOTE * 75);
  93. }
  94. // Пауза
  95. noTone(BUZZER_PIN);
  96. delay(DELAY_PAUSE);
  97. }

№7. Препятствие, стоп!

Научи шасси робота Ампи останавливаться перед препятствиями.

Obstacle.ino
  1. // Подключаем библиотеку для работы с дальномером
  2. #include <EasyUltrasonic.h>
  3.  
  4. // Подключаем библиотеку для работы с сервомоторами
  5. #include <Servo.h>
  6.  
  7. // Даём понятное имя пину 3 с пищалкой
  8. constexpr uint8_t BUZZER_PIN = 3;
  9.  
  10. // Даём понятные имена пинам 12 и 11 с дальномером
  11. constexpr uint8_t TRIG_PIN = 12;
  12. constexpr uint8_t ECHO_PIN = 11;
  13.  
  14. // Даём понятное имя пину 7 с левым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  16.  
  17. // Даём понятное имя пину 10 с правым сервомотором
  18. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  19.  
  20. // Задаём максимально доступную скорость сервомоторов
  21. // в сырых значениях по часовой и против часовой стрелки
  22. constexpr int SPEED_RAW_MAX_CW = 30;
  23. constexpr int SPEED_RAW_MAX_CCW = 150;
  24.  
  25. // Вычисляем показатель остановки сервомоторов в сырых значениях
  26. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  27.  
  28. // Создаём константы для калибровки скорости левого и правого мотора
  29. constexpr int SPEED_FACTOR_L = 0;
  30. constexpr int SPEED_FACTOR_R = 30;
  31.  
  32. // Создаём константу задержки езды
  33. constexpr int DELAY_DRIVE = 3000;
  34. // Создаём константу задержки остановки
  35. constexpr int DELAY_STOP = 1000;
  36. // Создаём константу задержки плавной остановки
  37. constexpr int DELAY_SMOOTH = 30;
  38.  
  39. // Создаём константу для хранения базовой частоты
  40. constexpr int FREQUENCY = 2000;
  41.  
  42. // Создаём константы для хранения минимальной и максимальной частоты
  43. constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
  44. constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
  45.  
  46. // Создаём константу для хранения тригера сигнализации в см
  47. constexpr int DISTANCE_DETOUR = 20;
  48.  
  49. // Создаём объект для работы с дальномером
  50. EasyUltrasonic distSensor;
  51.  
  52. // Создаём объект для работы с сервомоторами
  53. Servo servoL;
  54. Servo servoR;
  55.  
  56. // Прототип функции управления моторами
  57. void motorsDrive(int speedL, int speedR, bool smooth = true);
  58.  
  59. void setup() {
  60. // Настраиваем пин с пищалкой в режим выхода
  61. pinMode(BUZZER_PIN, OUTPUT);
  62. // Подключаем дальномер
  63. distSensor.attach(TRIG_PIN, ECHO_PIN);
  64. // Подключаем сервомоторы
  65. servoL.attach(SERVO_WHEEL_L_PIN);
  66. servoR.attach(SERVO_WHEEL_R_PIN);
  67. // Останавливаем сервомоторы
  68. motorsDrive(0, 0, false);
  69. // Передаём случайное число с пина A1
  70. // для последующей генерации случайных чисел
  71. randomSeed(analogRead(A1));
  72. // Включаем стартовую мелодию
  73. melodyStart();
  74. }
  75.  
  76. void loop() {
  77. // Задаём максимальную скорость вперёд
  78. motorsDrive(100, 100, false);
  79. // Считываем расстояние до объекта в см
  80. float distance = distSensor.getDistanceCM();
  81. // Задержка для стабилизации показаний с дальномера
  82. delay(10);
  83. // Если текущее расстояние до препятствия меньше тригера
  84. if (distance < DISTANCE_DETOUR) {
  85. // Останавливаем плавно сервомоторы
  86. motorsDrive(0, 0);
  87. // Запускаем мелодию R2-D2
  88. melodyR2D2();
  89. // Замораживаем программу
  90. while (1)
  91. ;
  92. }
  93. }
  94.  
  95. // Функция управления сервомоторами
  96. void motorsDrive(int speedL, int speedR, bool smooth) {
  97. // Создаём переменные для хранения текущей скорости
  98. // левого и правого мотора в сырых значениях
  99. int speedRawL = 0;
  100. int speedRawR = 0;
  101. // Создаём переменные для хранения обновлённой скорости
  102. // левого и правого мотора в сырых значениях
  103. int newSpeedRawL = 0;
  104. int newSpeedRawR = 0;
  105.  
  106. // Создаём переменные для хранения калибровочных коэффициентов скорости
  107. // левого и правого мотора
  108. int speedFactorL = 0;
  109. int speedFactorR = 0;
  110.  
  111. // Вычисляем калибровочные коэффициенты для моторов
  112. speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
  113. speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
  114.  
  115. // Получаем текущие показания моторов в сырых значениях
  116. speedRawL = servoL.read();
  117. speedRawR = servoR.read();
  118.  
  119. // Преобразуем показания скорости левого мотора
  120. if (speedL == 0) {
  121. newSpeedRawL = SPEED_RAW_STOP;
  122. } else if (speedL > 0) {
  123. speedL -= speedFactorL;
  124. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  125. } else if (speedL < 0) {
  126. speedL += speedFactorL;
  127. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  128. }
  129.  
  130. // Преобразуем показания скорости правого мотора
  131. if (speedR == 0) {
  132. newSpeedRawR = SPEED_RAW_STOP;
  133. } else if (speedR > 0) {
  134. speedR -= speedFactorR;
  135. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  136. } else if (speedR < 0) {
  137. speedR += speedFactorR;
  138. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  139. }
  140.  
  141. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  142. if (smooth) {
  143. // Плавное изменение скорости
  144. int steps = 10;
  145. for (int i = 0; i <= steps; i++) {
  146. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  147. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  148. servoL.write(newSpeedRawSmoothL);
  149. servoR.write(newSpeedRawSmoothR);
  150. delay(DELAY_SMOOTH);
  151. }
  152. } else {
  153. // Мгновенное изменение скорости
  154. servoL.write(newSpeedRawL);
  155. servoR.write(newSpeedRawR);
  156. }
  157. }
  158.  
  159. // Функция стартовой мелодии
  160. void melodyStart() {
  161. tone(BUZZER_PIN, 300, 500);
  162. delay(1000);
  163. tone(BUZZER_PIN, 400, 500);
  164. delay(1000);
  165. tone(BUZZER_PIN, 500, 500);
  166. delay(1000);
  167. tone(BUZZER_PIN, 700, 300);
  168. delay(1000);
  169. }
  170.  
  171. // Функция мелодии R2-D2
  172. void melodyR2D2() {
  173. // Вызываем функцию генератора последовательных длинных семплов
  174. toneLongSamples();
  175. // Вызываем функцию генератора непоследовательных коротких семплов
  176. toneShortSamples();
  177. }
  178.  
  179. // Функция генерации последовательных длинных семплов
  180. void toneLongSamples() {
  181. // Генерируем случайное количество семплов от 1 до 6
  182. int countSamples = random(1, 7);
  183. // Перебираем нумерацию семплов в цикле
  184. for (int i = 0; i < countSamples; i++) {
  185. // Генерируем случайное число: true или false
  186. bool typeSamples = random(0, 2);
  187. // Если тип семпла true
  188. if (typeSamples) {
  189. // Вызываем функцию генерации тона toneSlowDownFastUp:
  190. // Сначала медленный убывающий тон со случайными задержками
  191. // Затем быстрый возрастающий тон со случайными задержками
  192. toneSlowDownFastUp();
  193. } else {
  194. // Если тип семпла false
  195. // Вызываем функцию генерации тона toneSlowUpFastDown:
  196. // Сначала медленный возрастающий тон со случайными задержками
  197. // Затем быстрый убывающий тон со случайными задержками
  198. toneSlowUpFastDown();
  199. }
  200. }
  201. }
  202.  
  203. // Функция генерации непоследовательных коротких семплов
  204. void toneShortSamples() {
  205. // Генерируем случайное количество семплов от 3 до 9
  206. int countSamples = random(3, 10);
  207. // Генерируем случайную частоту на базе FREQUENCY
  208. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  209. for (int i = 0; i <= countSamples; i++) {
  210. // Генерируем случайный интервал на базе FREQUENCY
  211. int range = random(-FREQUENCY, FREQUENCY);
  212. tone(BUZZER_PIN, frequency + range);
  213. // Выполняем случайную задержку от 70 до 170 мс
  214. delay(random(70, 170));
  215. // Выключаем звук
  216. noTone(BUZZER_PIN);
  217. // Выполняем случайную задержку от 0 до 30 мс
  218. delay(random(0, 30));
  219. }
  220. }
  221.  
  222. // Функция генерации звуковой последовательности
  223. // Сначала медленный убывающий тон со случайными задержками
  224. // Затем быстрый возрастающий тон со случайными задержками
  225. void toneSlowDownFastUp() {
  226. // Генерируем случайную частоту на базе FREQUENCY
  227. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  228. // Генерируем медленный понижающий тон со случайными задержками
  229. for (int range = 0; range <= random(100, 1000); range++) {
  230. tone(BUZZER_PIN, (range * 2));
  231. delayMicroseconds(random(0, 1000));
  232. }
  233. // Генерируем быстрый повышающий тон со случайными задержками
  234. for (int range = 0; range <= random(100, 1000); range++) {
  235. tone(BUZZER_PIN, frequency + (range * 10));
  236. delayMicroseconds(random(0, 1000));
  237. }
  238. }
  239.  
  240. // Функция генерации звуковой последовательности
  241. // Сначала медленный возрастающий тон со случайными задержками
  242. // Затем быстрый убывающий тон со случайными задержками
  243. void toneSlowUpFastDown() {
  244. // Генерируем случайную частоту на базе FREQUENCY
  245. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  246. // Генерируем медленный возрастающий тон со случайными задержками
  247. for (int range = 0; range <= random(100, 1000); range++) {
  248. tone(BUZZER_PIN, (range * 2));
  249. delayMicroseconds(random(0, 1000));
  250. }
  251. // Генерируем быстрый понижающий тон со случайными задержками
  252. for (int range = 0; range <= random(100, 1000); range++) {
  253. tone(BUZZER_PIN, (range * 10));
  254. delayMicroseconds(random(0, 1000));
  255. }
  256. }

№8. Препятствие, поворот, поехали!

Научи шасси робота Ампи по-умному огибать препятствия.

ObstacleAvoidance.ino
  1. // Подключаем библиотеку для работы с дальномером
  2. #include <EasyUltrasonic.h>
  3.  
  4. // Подключаем библиотеку для работы с сервомоторами
  5. #include <Servo.h>
  6.  
  7. // Даём понятное имя пину 3 с пищалкой
  8. constexpr uint8_t BUZZER_PIN = 3;
  9.  
  10. // Даём понятные имена пинам 12 и 11 с дальномером
  11. constexpr uint8_t TRIG_PIN = 12;
  12. constexpr uint8_t ECHO_PIN = 11;
  13.  
  14. // Даём понятное имя пину 7 с левым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  16.  
  17. // Даём понятное имя пину 10 с правым сервомотором
  18. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  19.  
  20. // Задаём максимально доступную скорость сервомоторов
  21. // в сырых значениях по часовой и против часовой стрелки
  22. constexpr int SPEED_RAW_MAX_CW = 30;
  23. constexpr int SPEED_RAW_MAX_CCW = 150;
  24.  
  25. // Вычисляем показатель остановки сервомоторов в сырых значениях
  26. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  27.  
  28. // Создаём константы для калибровки скорости левого и правого мотора
  29. constexpr int SPEED_FACTOR_L = 0;
  30. constexpr int SPEED_FACTOR_R = 30;
  31.  
  32. // Создаём константу задержки езды
  33. constexpr int DELAY_DRIVE = 3000;
  34. // Создаём константу задержки остановки
  35. constexpr int DELAY_STOP = 1000;
  36. // Создаём константу задержки плавной остановки
  37. constexpr int DELAY_SMOOTH = 30;
  38.  
  39. // Создаём константу для хранения базовой частоты
  40. constexpr int FREQUENCY = 2000;
  41.  
  42. // Создаём константы для хранения минимальной и максимальной частоты
  43. constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
  44. constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
  45.  
  46. // Создаём константу для хранения тригера сигнализации в см
  47. constexpr int DISTANCE_DETOUR = 20;
  48.  
  49. // Создаём объект для работы с дальномером
  50. EasyUltrasonic distSensor;
  51.  
  52. // Создаём объект для работы с сервомоторами
  53. Servo servoL;
  54. Servo servoR;
  55.  
  56. // Создаём перечисление состояний робота с соответствующей переменной
  57. enum {
  58. ROBOT_DRIVE, // Робот едет вперёд
  59. ROBOT_DETECT_DETOUR, // Робот зафиксировал препятствие
  60. } robotState;
  61.  
  62. // Создаём перечисление направления движения робота с соответствующей переменной
  63. enum DirectionDetours {
  64. LEFT,
  65. RIGHT,
  66. } direction;
  67.  
  68. // Прототип функции управления моторами
  69. void motorsDrive(int speedL, int speedR, bool smooth = true);
  70.  
  71. void setup() {
  72. // Настраиваем пин с пищалкой в режим выхода
  73. pinMode(BUZZER_PIN, OUTPUT);
  74. // Подключаем дальномер
  75. distSensor.attach(TRIG_PIN, ECHO_PIN);
  76. // Подключаем сервомоторы
  77. servoL.attach(SERVO_WHEEL_L_PIN);
  78. servoR.attach(SERVO_WHEEL_R_PIN);
  79. // Останавливаем сервомоторы
  80. motorsDrive(0, 0, false);
  81. // Передаём случайное число с пина A1
  82. // для последующей генерации случайных чисел
  83. randomSeed(analogRead(A1));
  84. // Включаем стартовую мелодию
  85. melodyStart();
  86. // Устанавливаем режим «Робот едет вперёд»
  87. robotState = ROBOT_DRIVE;
  88. }
  89.  
  90. void loop() {
  91. // Если установлен режим «Робот едет вперёд»
  92. if (robotState == ROBOT_DRIVE) {
  93. // Переходим в функцию обработки режима «Робот едет вперёд»
  94. handleRobotDrive();
  95. }
  96. // Если установлен режим «Робот зафиксировал препятствие»
  97. if (robotState == ROBOT_DETECT_DETOUR) {
  98. // Переходим в функцию обработки режима «Робот зафиксировал препятствие»
  99. handleRobotDetectDetour();
  100. }
  101. }
  102.  
  103. // Функция обработки режима «Робот едет вперёд»
  104. void handleRobotDrive() {
  105. // Задаём максимальную скорость вперёд
  106. motorsDrive(100, 100, false);
  107. // Считываем расстояние до объекта в см
  108. float distance = distSensor.getDistanceCM();
  109. // Задержка для стабилизации показаний с дальномера
  110. delay(10);
  111. // Если текущее расстояние до препятствия меньше тригера
  112. if (distance < DISTANCE_DETOUR) {
  113. // Устанавливаем режим «Робот зафиксировал препятствие»
  114. robotState = ROBOT_DETECT_DETOUR;
  115. }
  116. }
  117.  
  118. // Функция обработки режима «Робот зафиксировал препятствие»
  119. void handleRobotDetectDetour() {
  120. // Останавливаем плавно сервомоторы
  121. motorsDrive(0, 0);
  122. // Запускаем мелодию R2-D2
  123. melodyR2D2();
  124. // Ждём 1 сек
  125. delay(1000);
  126. // Объезжаем препятствие слева 500 мс
  127. motorsDetourBarrier(LEFT, 500);
  128. // Устанавливаем режим «Робот едет вперёд»
  129. robotState = ROBOT_DRIVE;
  130. }
  131.  
  132. // Функция объезда препятствие
  133. void motorsDetourBarrier(DirectionDetours direction, int delayDrive) {
  134. // Выбираем направления заднего хода для разворота
  135. if (direction == LEFT) {
  136. motorsDrive(-50, 0, false);
  137. } else if (direction == RIGHT) {
  138. motorsDrive(0, -50, false);
  139. }
  140. // Ждём интервал задержки езды
  141. delay(delayDrive);
  142. // Останавливаем сервомоторы с плавным торможением
  143. motorsDrive(0, 0);
  144. // Ждём интервал задержки остановки
  145. delay(1000);
  146. }
  147.  
  148. // Функция управления сервомоторами
  149. void motorsDrive(int speedL, int speedR, bool smooth) {
  150. // Создаём переменные для хранения текущей скорости
  151. // левого и правого мотора в сырых значениях
  152. int speedRawL = 0;
  153. int speedRawR = 0;
  154. // Создаём переменные для хранения обновлённой скорости
  155. // левого и правого мотора в сырых значениях
  156. int newSpeedRawL = 0;
  157. int newSpeedRawR = 0;
  158.  
  159. // Создаём переменные для хранения калибровочных коэффициентов скорости
  160. // левого и правого мотора
  161. int speedFactorL = 0;
  162. int speedFactorR = 0;
  163.  
  164. // Вычисляем калибровочные коэффициенты для моторов
  165. speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
  166. speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
  167.  
  168. // Получаем текущие показания моторов в сырых значениях
  169. speedRawL = servoL.read();
  170. speedRawR = servoR.read();
  171.  
  172. // Преобразуем показания скорости левого мотора
  173. if (speedL == 0) {
  174. newSpeedRawL = SPEED_RAW_STOP;
  175. } else if (speedL > 0) {
  176. speedL -= speedFactorL;
  177. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  178. } else if (speedL < 0) {
  179. speedL += speedFactorL;
  180. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  181. }
  182.  
  183. // Преобразуем показания скорости правого мотора
  184. if (speedR == 0) {
  185. newSpeedRawR = SPEED_RAW_STOP;
  186. } else if (speedR > 0) {
  187. speedR -= speedFactorR;
  188. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  189. } else if (speedR < 0) {
  190. speedR += speedFactorR;
  191. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  192. }
  193.  
  194. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  195. if (smooth) {
  196. // Плавное изменение скорости
  197. int steps = 10;
  198. for (int i = 0; i <= steps; i++) {
  199. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  200. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  201. servoL.write(newSpeedRawSmoothL);
  202. servoR.write(newSpeedRawSmoothR);
  203. delay(DELAY_SMOOTH);
  204. }
  205. } else {
  206. // Мгновенное изменение скорости
  207. servoL.write(newSpeedRawL);
  208. servoR.write(newSpeedRawR);
  209. }
  210. }
  211.  
  212. // Функция стартовой мелодии
  213. void melodyStart() {
  214. tone(BUZZER_PIN, 300, 500);
  215. delay(1000);
  216. tone(BUZZER_PIN, 400, 500);
  217. delay(1000);
  218. tone(BUZZER_PIN, 500, 500);
  219. delay(1000);
  220. tone(BUZZER_PIN, 700, 300);
  221. delay(1000);
  222. }
  223.  
  224. // Функция мелодии R2-D2
  225. void melodyR2D2() {
  226. // Вызываем функцию генератора последовательных длинных семплов
  227. toneLongSamples();
  228. // Вызываем функцию генератора непоследовательных коротких семплов
  229. toneShortSamples();
  230. }
  231.  
  232. // Функция генерации последовательных длинных семплов
  233. void toneLongSamples() {
  234. // Генерируем случайное количество семплов от 1 до 6
  235. int countSamples = random(1, 7);
  236. // Перебираем нумерацию семплов в цикле
  237. for (int i = 0; i < countSamples; i++) {
  238. // Генерируем случайное число: true или false
  239. bool typeSamples = random(0, 2);
  240. // Если тип семпла true
  241. if (typeSamples) {
  242. // Вызываем функцию генерации тона toneSlowDownFastUp:
  243. // Сначала медленный убывающий тон со случайными задержками
  244. // Затем быстрый возрастающий тон со случайными задержками
  245. toneSlowDownFastUp();
  246. } else {
  247. // Если тип семпла false
  248. // Вызываем функцию генерации тона toneSlowUpFastDown:
  249. // Сначала медленный возрастающий тон со случайными задержками
  250. // Затем быстрый убывающий тон со случайными задержками
  251. toneSlowUpFastDown();
  252. }
  253. }
  254. }
  255.  
  256. // Функция генерации непоследовательных коротких семплов
  257. void toneShortSamples() {
  258. // Генерируем случайное количество семплов от 3 до 9
  259. int countSamples = random(3, 10);
  260. // Генерируем случайную частоту на базе FREQUENCY
  261. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  262. for (int i = 0; i <= countSamples; i++) {
  263. // Генерируем случайный интервал на базе FREQUENCY
  264. int range = random(-FREQUENCY, FREQUENCY);
  265. tone(BUZZER_PIN, frequency + range);
  266. // Выполняем случайную задержку от 70 до 170 мс
  267. delay(random(70, 170));
  268. // Выключаем звук
  269. noTone(BUZZER_PIN);
  270. // Выполняем случайную задержку от 0 до 30 мс
  271. delay(random(0, 30));
  272. }
  273. }
  274.  
  275. // Функция генерации звуковой последовательности
  276. // Сначала медленный убывающий тон со случайными задержками
  277. // Затем быстрый возрастающий тон со случайными задержками
  278. void toneSlowDownFastUp() {
  279. // Генерируем случайную частоту на базе FREQUENCY
  280. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  281. // Генерируем медленный понижающий тон со случайными задержками
  282. for (int range = 0; range <= random(100, 1000); range++) {
  283. tone(BUZZER_PIN, (range * 2));
  284. delayMicroseconds(random(0, 1000));
  285. }
  286. // Генерируем быстрый повышающий тон со случайными задержками
  287. for (int range = 0; range <= random(100, 1000); range++) {
  288. tone(BUZZER_PIN, frequency + (range * 10));
  289. delayMicroseconds(random(0, 1000));
  290. }
  291. }
  292.  
  293. // Функция генерации звуковой последовательности
  294. // Сначала медленный возрастающий тон со случайными задержками
  295. // Затем быстрый убывающий тон со случайными задержками
  296. void toneSlowUpFastDown() {
  297. // Генерируем случайную частоту на базе FREQUENCY
  298. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  299. // Генерируем медленный возрастающий тон со случайными задержками
  300. for (int range = 0; range <= random(100, 1000); range++) {
  301. tone(BUZZER_PIN, (range * 2));
  302. delayMicroseconds(random(0, 1000));
  303. }
  304. // Генерируем быстрый понижающий тон со случайными задержками
  305. for (int range = 0; range <= random(100, 1000); range++) {
  306. tone(BUZZER_PIN, (range * 10));
  307. delayMicroseconds(random(0, 1000));
  308. }
  309. }

№9. Трусливый бот

Пусть шасси робота Ампи убегает прочь от приближающихся объектов.

DriveAway.ino
  1. // Подключаем библиотеку для работы с дальномером
  2. #include <EasyUltrasonic.h>
  3.  
  4. // Подключаем библиотеку для работы с сервомоторами
  5. #include <Servo.h>
  6.  
  7. // Даём понятное имя пину 3 с пищалкой
  8. constexpr uint8_t BUZZER_PIN = 3;
  9.  
  10. // Даём понятные имена пинам 12 и 11 с дальномером
  11. constexpr uint8_t TRIG_PIN = 12;
  12. constexpr uint8_t ECHO_PIN = 11;
  13.  
  14. // Даём понятное имя пину 7 с левым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  16.  
  17. // Даём понятное имя пину 10 с правым сервомотором
  18. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  19.  
  20. // Задаём максимально доступную скорость сервомоторов
  21. // в сырых значениях по часовой и против часовой стрелки
  22. constexpr int SPEED_RAW_MAX_CW = 30;
  23. constexpr int SPEED_RAW_MAX_CCW = 150;
  24.  
  25. // Вычисляем показатель остановки сервомоторов в сырых значениях
  26. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  27.  
  28. // Создаём константы для калибровки скорости левого и правого мотора
  29. constexpr int SPEED_FACTOR_L = 0;
  30. constexpr int SPEED_FACTOR_R = 30;
  31.  
  32. // Создаём константу задержки езды
  33. constexpr int DELAY_DRIVE = 3000;
  34. // Создаём константу задержки остановки
  35. constexpr int DELAY_STOP = 1000;
  36. // Создаём константу задержки плавной остановки
  37. constexpr int DELAY_SMOOTH = 30;
  38.  
  39. // Создаём константу для хранения базовой частоты
  40. constexpr int FREQUENCY = 2000;
  41.  
  42. // Создаём константы для хранения минимальной и максимальной частоты
  43. constexpr int MIN_FREQUENCY = FREQUENCY - (0.25 * FREQUENCY);
  44. constexpr int MAX_FREQUENCY = FREQUENCY + (0.25 * FREQUENCY);
  45.  
  46. // Создаём константу для хранения тригера сигнализации в см
  47. constexpr int DISTANCE_DETOUR = 20;
  48.  
  49. // Создаём объект для работы с дальномером
  50. EasyUltrasonic distSensor;
  51.  
  52. // Создаём объект для работы с сервомоторами
  53. Servo servoL;
  54. Servo servoR;
  55.  
  56. // Создаём перечисление состояний робота с соответствующей переменной
  57. enum {
  58. ROBOT_STANDING, // Робот стоит на месте
  59. ROBOT_STANDING_DETECT_DETOUR, // Робот стоял на месте и зафиксировал препятствие
  60. ROBOT_DRIVE, // Робот едет вперёд
  61. ROBOT_DRIVE_DETECT_DETOUR, // Робот ехал вперёд и зафиксировал препятствие
  62. } robotState;
  63.  
  64. // Создаём перечисление направления движения робота с соответствующей переменной
  65. enum DirectionDetours {
  66. LEFT,
  67. RIGHT,
  68. } direction;
  69.  
  70. // Прототип функции управления моторами
  71. void motorsDrive(int speedL, int speedR, bool smooth = true);
  72.  
  73. void setup() {
  74. // Настраиваем пин с пищалкой в режим выхода
  75. pinMode(BUZZER_PIN, OUTPUT);
  76. // Подключаем дальномер
  77. distSensor.attach(TRIG_PIN, ECHO_PIN);
  78. // Подключаем сервомоторы
  79. servoL.attach(SERVO_WHEEL_L_PIN);
  80. servoR.attach(SERVO_WHEEL_R_PIN);
  81. // Останавливаем сервомоторы
  82. motorsDrive(0, 0, false);
  83. // Передаём случайное число с пина A1
  84. // для последующей генерации случайных чисел
  85. randomSeed(analogRead(A1));
  86. // Включаем стартовую мелодию
  87. melodyStart();
  88. // Устанавливаем режим «Робот стоит на месте»
  89. robotState = ROBOT_STANDING;
  90. }
  91.  
  92. void loop() {
  93. // Если установлен режим «Робот стоит на месте»
  94. if (robotState == ROBOT_STANDING) {
  95. // Переходим в функцию обработки режима «Робот стоит на месте»
  96. handleRobotStanding();
  97. }
  98. // Если установлен режим «Робот стоял на месте и зафиксировал препятствие»
  99. if (robotState == ROBOT_STANDING_DETECT_DETOUR) {
  100. // Переходим в функцию обработки режима «Робот стоял на месте и зафиксировал препятствие»
  101. handleRobotStandingDetectDetour();
  102. }
  103. // Если установлен режим «Робот едет вперёд»
  104. if (robotState == ROBOT_DRIVE) {
  105. // Переходим в функцию обработки режима «Робот едет вперёд»
  106. handleRobotDrive();
  107. }
  108. // Если установлен режим «Робот ехал вперёд и зафиксировал препятствие»
  109. if (robotState == ROBOT_DRIVE_DETECT_DETOUR) {
  110. // Переходим в функцию обработки режима «Робот ехал вперёд и зафиксировал препятствие»
  111. handleRobotDriveDetectDetour();
  112. }
  113. }
  114.  
  115. // Функция обработки режима «Робот стоит на месте»
  116. void handleRobotStanding() {
  117. // Считываем расстояние до объекта в см
  118. float distance = distSensor.getDistanceCM();
  119. // Задержка для стабилизации показаний с дальномера
  120. delay(10);
  121. // Если текущее расстояние до препятствия меньше тригера
  122. if (distance < DISTANCE_DETOUR) {
  123. // Устанавливаем режим «Робот стоял на месте и зафиксировал препятствие»
  124. robotState = ROBOT_STANDING_DETECT_DETOUR;
  125. }
  126. }
  127.  
  128. // Функция обработки режима «Робот стоял на месте и зафиксировал препятствие»
  129. void handleRobotStandingDetectDetour() {
  130. // Запускаем мелодию R2-D2
  131. melodyR2D2();
  132. // Ждём 1 сек
  133. delay(1000);
  134. // Объезжаем препятствие слева 1000 мс
  135. motorsDetourBarrier(LEFT, 1000);
  136. // Устанавливаем режим «Робот едет вперёд»
  137. robotState = ROBOT_DRIVE;
  138. }
  139.  
  140. // Функция обработки режима «Робот едет вперёд»
  141. void handleRobotDrive() {
  142. // Задаём максимальную скорость вперёд
  143. motorsDrive(100, 100, false);
  144. // Считываем расстояние до объекта в см
  145. float dist = distSensor.getDistanceCM();
  146. // Задержка для стабилизации показаний с дальномера
  147. delay(10);
  148. // Если текущее расстояние до препятствия меньше тригера
  149. if (dist < DISTANCE_DETOUR) {
  150. // Устанавливаем режим «Робот зафиксировал препятствие»
  151. robotState = ROBOT_DRIVE_DETECT_DETOUR;
  152. }
  153. }
  154.  
  155. // Функция обработки режима «Робот зафиксировал препятствие»
  156. void handleRobotDriveDetectDetour() {
  157. // Останавливаем плавно сервомоторы
  158. motorsDrive(0, 0);
  159. // Запускаем мелодию R2-D2
  160. melodyR2D2();
  161. // Ждём 1 сек
  162. delay(1000);
  163. // Объезжаем препятствие слева 500 мс
  164. motorsDetourBarrier(LEFT, 500);
  165. // Устанавливаем режим «Робот едет вперёд»
  166. robotState = ROBOT_DRIVE;
  167. }
  168.  
  169. // Функция объезда препятствие
  170. void motorsDetourBarrier(DirectionDetours direction, int delayDrive) {
  171. // Выбираем направления заднего хода для разворота
  172. if (direction == LEFT) {
  173. motorsDrive(-50, 0, false);
  174. } else if (direction == RIGHT) {
  175. motorsDrive(0, -50, false);
  176. }
  177. // Ждём интервал задержки езды
  178. delay(delayDrive);
  179. // Останавливаем плавно сервомоторы
  180. motorsDrive(0, 0);
  181. // Ждём интервал задержки остановки
  182. delay(1000);
  183. }
  184.  
  185. // Функция управления сервомоторами
  186. void motorsDrive(int speedL, int speedR, bool smooth) {
  187. // Создаём переменные для хранения текущей скорости
  188. // левого и правого мотора в сырых значениях
  189. int speedRawL = 0;
  190. int speedRawR = 0;
  191. // Создаём переменные для хранения обновлённой скорости
  192. // левого и правого мотора в сырых значениях
  193. int newSpeedRawL = 0;
  194. int newSpeedRawR = 0;
  195.  
  196. // Создаём переменные для хранения калибровочных коэффициентов скорости
  197. // левого и правого мотора
  198. int speedFactorL = 0;
  199. int speedFactorR = 0;
  200.  
  201. // Вычисляем калибровочные коэффициенты для моторов
  202. speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
  203. speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
  204.  
  205. // Получаем текущие показания моторов в сырых значениях
  206. speedRawL = servoL.read();
  207. speedRawR = servoR.read();
  208.  
  209. // Преобразуем показания скорости левого мотора
  210. if (speedL == 0) {
  211. newSpeedRawL = SPEED_RAW_STOP;
  212. } else if (speedL > 0) {
  213. speedL -= speedFactorL;
  214. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  215. } else if (speedL < 0) {
  216. speedL += speedFactorL;
  217. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  218. }
  219.  
  220. // Преобразуем показания скорости правого мотора
  221. if (speedR == 0) {
  222. newSpeedRawR = SPEED_RAW_STOP;
  223. } else if (speedR > 0) {
  224. speedR -= speedFactorR;
  225. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  226. } else if (speedR < 0) {
  227. speedR += speedFactorR;
  228. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  229. }
  230.  
  231. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  232. if (smooth) {
  233. // Плавное изменение скорости
  234. int steps = 10;
  235. for (int i = 0; i <= steps; i++) {
  236. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  237. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  238. servoL.write(newSpeedRawSmoothL);
  239. servoR.write(newSpeedRawSmoothR);
  240. delay(DELAY_SMOOTH);
  241. }
  242. } else {
  243. // Мгновенное изменение скорости
  244. servoL.write(newSpeedRawL);
  245. servoR.write(newSpeedRawR);
  246. }
  247. }
  248.  
  249. // Функция стартовой мелодии
  250. void melodyStart() {
  251. tone(BUZZER_PIN, 300, 500);
  252. delay(1000);
  253. tone(BUZZER_PIN, 400, 500);
  254. delay(1000);
  255. tone(BUZZER_PIN, 500, 500);
  256. delay(1000);
  257. tone(BUZZER_PIN, 700, 300);
  258. delay(1000);
  259. }
  260.  
  261. // Функция мелодии R2-D2
  262. void melodyR2D2() {
  263. // Вызываем функцию генератора последовательных длинных семплов
  264. toneLongSamples();
  265. // Вызываем функцию генератора непоследовательных коротких семплов
  266. toneShortSamples();
  267. }
  268.  
  269. // Функция генерации последовательных длинных семплов
  270. void toneLongSamples() {
  271. // Генерируем случайное количество семплов от 1 до 6
  272. int countSamples = random(1, 7);
  273. // Перебираем нумерацию семплов в цикле
  274. for (int i = 0; i < countSamples; i++) {
  275. // Генерируем случайное число: true или false
  276. bool typeSamples = random(0, 2);
  277. // Если тип семпла true
  278. if (typeSamples) {
  279. // Вызываем функцию генерации тона toneSlowDownFastUp:
  280. // Сначала медленный убывающий тон со случайными задержками
  281. // Затем быстрый возрастающий тон со случайными задержками
  282. toneSlowDownFastUp();
  283. } else {
  284. // Если тип семпла false
  285. // Вызываем функцию генерации тона toneSlowUpFastDown:
  286. // Сначала медленный возрастающий тон со случайными задержками
  287. // Затем быстрый убывающий тон со случайными задержками
  288. toneSlowUpFastDown();
  289. }
  290. }
  291. }
  292.  
  293. // Функция генерации непоследовательных коротких семплов
  294. void toneShortSamples() {
  295. // Генерируем случайное количество семплов от 3 до 9
  296. int countSamples = random(3, 10);
  297. // Генерируем случайную частоту на базе FREQUENCY
  298. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  299. for (int i = 0; i <= countSamples; i++) {
  300. // Генерируем случайный интервал на базе FREQUENCY
  301. int range = random(-FREQUENCY, FREQUENCY);
  302. tone(BUZZER_PIN, frequency + range);
  303. // Выполняем случайную задержку от 70 до 170 мс
  304. delay(random(70, 170));
  305. // Выключаем звук
  306. noTone(BUZZER_PIN);
  307. // Выполняем случайную задержку от 0 до 30 мс
  308. delay(random(0, 30));
  309. }
  310. }
  311.  
  312. // Функция генерации звуковой последовательности
  313. // Сначала медленный убывающий тон со случайными задержками
  314. // Затем быстрый возрастающий тон со случайными задержками
  315. void toneSlowDownFastUp() {
  316. // Генерируем случайную частоту на базе FREQUENCY
  317. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  318. // Генерируем медленный понижающий тон со случайными задержками
  319. for (int range = 0; range <= random(100, 1000); range++) {
  320. tone(BUZZER_PIN, (range * 2));
  321. delayMicroseconds(random(0, 1000));
  322. }
  323. // Генерируем быстрый повышающий тон со случайными задержками
  324. for (int range = 0; range <= random(100, 1000); range++) {
  325. tone(BUZZER_PIN, frequency + (range * 10));
  326. delayMicroseconds(random(0, 1000));
  327. }
  328. }
  329.  
  330. // Функция генерации звуковой последовательности
  331. // Сначала медленный возрастающий тон со случайными задержками
  332. // Затем быстрый убывающий тон со случайными задержками
  333. void toneSlowUpFastDown() {
  334. // Генерируем случайную частоту на базе FREQUENCY
  335. int frequency = random(MIN_FREQUENCY, MAX_FREQUENCY);
  336. // Генерируем медленный возрастающий тон со случайными задержками
  337. for (int range = 0; range <= random(100, 1000); range++) {
  338. tone(BUZZER_PIN, (range * 2));
  339. delayMicroseconds(random(0, 1000));
  340. }
  341. // Генерируем быстрый понижающий тон со случайными задержками
  342. for (int range = 0; range <= random(100, 1000); range++) {
  343. tone(BUZZER_PIN, (range * 10));
  344. delayMicroseconds(random(0, 1000));
  345. }
  346. }

№10. Следопыт

Сделай из робота Ампи настоящего сыщика: пусть он пресле- дует замеченные дальномером объекты.

Detective.ino
  1. // Подключаем библиотеку для работы с дальномером
  2. #include <EasyUltrasonic.h>
  3.  
  4. // Подключаем библиотеку для работы с сервомоторами
  5. #include <Servo.h>
  6.  
  7. // Даём понятное имя пину 3 с пищалкой
  8. constexpr uint8_t BUZZER_PIN = 3;
  9.  
  10. // Даём понятные имена пинам 12 и 11 с дальномером
  11. constexpr uint8_t TRIG_PIN = 12;
  12. constexpr uint8_t ECHO_PIN = 11;
  13.  
  14. // Даём понятное имя пину 7 с левым сервомотором
  15. constexpr uint8_t SERVO_WHEEL_L_PIN = 7;
  16.  
  17. // Даём понятное имя пину 10 с правым сервомотором
  18. constexpr uint8_t SERVO_WHEEL_R_PIN = 10;
  19.  
  20. // Задаём максимально доступную скорость сервомоторов
  21. // в сырых значениях по часовой и против часовой стрелки
  22. constexpr int SPEED_RAW_MAX_CW = 30;
  23. constexpr int SPEED_RAW_MAX_CCW = 150;
  24.  
  25. // Вычисляем показатель остановки сервомоторов в сырых значениях
  26. constexpr int SPEED_RAW_STOP = (SPEED_RAW_MAX_CW + SPEED_RAW_MAX_CCW) / 2;
  27.  
  28. // Создаём константы для калибровки скорости левого и правого мотора
  29. constexpr int SPEED_FACTOR_L = 0;
  30. constexpr int SPEED_FACTOR_R = 30;
  31.  
  32. // Создаём константу задержки езды
  33. constexpr int DELAY_DRIVE = 3000;
  34. // Создаём константу задержки остановки
  35. constexpr int DELAY_STOP = 1000;
  36. // Создаём константу задержки плавной остановки
  37. constexpr int DELAY_SMOOTH = 30;
  38.  
  39. // Создаём константу для желаемого расстояние зоны поиска объекта в см
  40. constexpr int DISTANCE_RANGE = 100;
  41.  
  42. // Создаём константу для желаемого расстояние до объекта в см
  43. constexpr int DISTANCE_TARGET = 30;
  44. // Создаём константы для хранения желаемой зоны до объекта
  45. constexpr int MIN_DISTANCE_TARGET = DISTANCE_TARGET - (0.25 * DISTANCE_TARGET);
  46. constexpr int MAX_DISTANCE_TARGET = DISTANCE_TARGET + (0.25 * DISTANCE_TARGET);
  47.  
  48. // Создаём объект для работы с дальномером
  49. EasyUltrasonic distSensor;
  50.  
  51. // Создаём объект для работы с сервомоторами
  52. Servo servoL;
  53. Servo servoR;
  54.  
  55. // Прототип функции управления моторами
  56. void motorsDrive(int speedL, int speedR, bool smooth = true);
  57.  
  58. void setup() {
  59. // Настраиваем пин с пищалкой в режим выхода
  60. pinMode(BUZZER_PIN, OUTPUT);
  61. // Подключаем дальномер
  62. distSensor.attach(TRIG_PIN, ECHO_PIN);
  63. // Подключаем сервомоторы
  64. servoL.attach(SERVO_WHEEL_L_PIN);
  65. servoR.attach(SERVO_WHEEL_R_PIN);
  66. // Останавливаем сервомоторы
  67. motorsDrive(0, 0, false);
  68. // Включаем стартовую мелодию
  69. melodyStart();
  70. }
  71.  
  72. void loop() {
  73. // Считываем расстояние до объекта в см
  74. float distance = distSensor.getDistanceCM();
  75. // Задержка для стабилизации показаний с дальномера
  76. delay(10);
  77. // Проверяем расстояние до объекта
  78. if (distance > DISTANCE_RANGE) {
  79. // Если в зоне поиска робота нет объектов, стоим
  80. motorsDrive(0, 0);
  81. } else if (distance < MIN_DISTANCE_TARGET) {
  82. // Если робот слишком близко к цели, едем назад
  83. motorsDrive(-50, -50);
  84. } else if (distance > MIN_DISTANCE_TARGET && distance < MAX_DISTANCE_TARGET) {
  85. // Если робот в зоне слежения цели, стоим
  86. motorsDrive(0, 0);
  87. } else if (distance > MAX_DISTANCE_TARGET) {
  88. // Если робот далеко от цели, едем вперёд
  89. motorsDrive(50, 50);
  90. }
  91. }
  92.  
  93. // Функция управления сервомоторами
  94. void motorsDrive(int speedL, int speedR, bool smooth) {
  95. // Создаём переменные для хранения текущей скорости
  96. // левого и правого мотора в сырых значениях
  97. int speedRawL = 0;
  98. int speedRawR = 0;
  99. // Создаём переменные для хранения обновлённой скорости
  100. // левого и правого мотора в сырых значениях
  101. int newSpeedRawL = 0;
  102. int newSpeedRawR = 0;
  103.  
  104. // Создаём переменные для хранения калибровочных коэффициентов скорости
  105. // левого и правого мотора
  106. int speedFactorL = 0;
  107. int speedFactorR = 0;
  108.  
  109. // Вычисляем калибровочные коэффициенты для моторов
  110. speedFactorL = (SPEED_FACTOR_L * speedL) / 100;
  111. speedFactorR = (SPEED_FACTOR_R * speedR) / 100;
  112.  
  113. // Получаем текущие показания моторов в сырых значениях
  114. speedRawL = servoL.read();
  115. speedRawR = servoR.read();
  116.  
  117. // Преобразуем показания скорости левого мотора
  118. if (speedL == 0) {
  119. newSpeedRawL = SPEED_RAW_STOP;
  120. } else if (speedL > 0) {
  121. speedL -= speedFactorL;
  122. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  123. } else if (speedL < 0) {
  124. speedL += speedFactorL;
  125. newSpeedRawL = map(abs(speedL), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  126. }
  127.  
  128. // Преобразуем показания скорости правого мотора
  129. if (speedR == 0) {
  130. newSpeedRawR = SPEED_RAW_STOP;
  131. } else if (speedR > 0) {
  132. speedR -= speedFactorR;
  133. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CW);
  134. } else if (speedR < 0) {
  135. speedR += speedFactorR;
  136. newSpeedRawR = map(abs(speedR), 0, 100, SPEED_RAW_STOP, SPEED_RAW_MAX_CCW);
  137. }
  138.  
  139. // Проверяем состояние флага: плавное или мгновенное изменение скорости
  140. if (smooth) {
  141. // Плавное изменение скорости
  142. int steps = 10;
  143. for (int i = 0; i <= steps; i++) {
  144. int newSpeedRawSmoothL = map(i, 0, steps, speedRawL, newSpeedRawL);
  145. int newSpeedRawSmoothR = map(i, 0, steps, speedRawR, newSpeedRawR);
  146. servoL.write(newSpeedRawSmoothL);
  147. servoR.write(newSpeedRawSmoothR);
  148. delay(DELAY_SMOOTH);
  149. }
  150. } else {
  151. // Мгновенное изменение скорости
  152. servoL.write(newSpeedRawL);
  153. servoR.write(newSpeedRawR);
  154. }
  155. }
  156.  
  157. // Функция стартовой мелодии
  158. void melodyStart() {
  159. tone(BUZZER_PIN, 300, 500);
  160. delay(1000);
  161. tone(BUZZER_PIN, 400, 500);
  162. delay(1000);
  163. tone(BUZZER_PIN, 500, 500);
  164. delay(1000);
  165. tone(BUZZER_PIN, 700, 300);
  166. delay(1000);
  167. }

Ресурсы

Софт

Библиотеки