Блог о программировании, электронике и рыбалке

Ведроид-мобиль — робот на Arduino — Часть 4. Подключаем ультразвуковой дальномер

arduino роботВ этой статье я опишу процесс создания шилда управления роботом, подключение ультразвукового дальномера и реализацию алгоритма объезда препятствий. На выходе у нас должен получиться полностью автономный робот.

А прошлой статье я описывал процесс реализации управления роботом по Bluetooth через смартфон на Android. Это был первый режим работы робота. После этой статьи у нас появится второй режим. В будущем я планирую добавить еще несколько.

Создание шилда управления роботом

Для переключения между различными режимами работы я решил сделать отдельный шилд. В прошлый раз я уже использовал Proto Shield. Сегодня я его немного модернизирую под свои потребности.

Для этого нам понадобятся следующие детали:

  • Светодиоды - 7 штук
  • Кнопки - 3 штуки
  • Резисторы на 220 Ом - 6 штук
  • Резисторы на 10 кОм - 2 штуки
  • Перемычки - 5 штук
  • Разъём PBS (мама) на 16 контактов - 1 штука
  • Миниатюрная макетная плата - 1 штука

Все компоненты запаиваем на Proto Shield по указанной схеме (вид со стороны деталей):arduino робот

Размещение элементов на плате:

arduino робот

В левом нижнем углу я вывел кнопку RESET. Она замыкает выводы RESET и GND. В левом верхнем - разъем подключения сервоприводов. Вверху светодиод с 13 дискретного вывода. Справа 2 кнопки переключения режимов (след / пред).

Каждая кнопка подтянута к земле резистором на 10 кОм.

arduino робот

Далее размещены 6 светодиодов, которые подключены к панельке контактов через резисторы на 220 Ом.

arduino робот

Светодиоды будут служить индикаторами режимов работы робота.

Для разводки дополнительных модулей, я еще решил добавить в шилд управления миниатюрную макетную плату.

arduino робот

Подключение шилда управления роботом

Подключим провода к разъему на 16 контактов. Описывать буду назначение контактов сверху вниз. LED 1..6 - выводы светодиодов, BTN 1..2 - кнопки.

  • 1 - LED 1 - к 22 дискретному выводу Arduino
  • 2
  • 3
  • 4 - LED 2 - к 23 дискретному выводу Arduino Mega 2560
  • 5
  • 6 - BTN 1 - к 28 дискретному выводу Arduino Mega 2560
  • 7 - LED 3 - к 24 дискретному выводу Arduino Mega 2560
  • 8 - GND - к GND Arduino Mega 2560
  • 9 - +5 V - к +5 V Arduino Mega 2560
  • 10 - LED 4 - к 25 дискретному выводу Arduino Mega 2560
  • 11 - BTN 2 - к 29 дискретному выводу Arduino Mega 2560
  • 12
  • 13 - LED 5 - к 26 дискретному выводу Arduino Mega 2560
  • 14
  • 15
  • 16 - LED 6 - к 27 дискретному выводу Arduino Mega 2560

Сразу восстановим подключение Bluetooth модуля JY-MCU к Arduino Mega 2560

  • VCC на JY-MCU подключаем к +5В Arduino
  • GND на JY-MCU подключаем к GND Arduino
  • TXT на JY-MCU подключаем к дискретному PIN 50 на Arduino
  • RXD на JY-MCU подключаем к дискретному PIN 51 на Arduino

arduino робот

Подключение ультразвукового дальномера HC-SR04

Процесс подключения ультразвукового дальномера HC-SR04 к Arduino  и работу с ним я описывал ранее. В тонкости в этот раз вдаваться не буду, а лучше подробно распишу как я его закрепил на сервоприводе.

Для создания крепления под ультразвуковой дальномер HC-SR04 я использовал кусок платы от Proto Shield и панельку контактов.

arduino робот

Откусил от панельки контактов две части по 4 контакта и запаял их на плату параллельно.

arduino робот

arduino робот

Перед подключением дальномера я сперва “раскорячил” его контакты, чтобы они плотно держались в разъеме.

arduino робот

Проковырял в плате дырку под болт.

arduino робот

Закрепил модуль на сервоприводе.

arduino робот

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

arduino робот

Осталось только подключить провода к контактной панельке на плате дальномера и завести их на контакты Arduino Mega 2560. Этим и займемся.

  • VCC HC-SR04 подключим к +5V на Arduino Mega 2560
  • Trig HC-SR04 к цифровому пину 31 на Arduino Mega 2560
  • Echo HC-SR04 к цифровому пину 30 на Arduino Mega 2560
  • GND HC-SR04 к GND на Arduino Mega 2560

Алгоритм объезда препятствий

С алгоритмом я особо не заморачивался. Все достаточно просто и интуитивно понятно.

Из исходного положения проверяем расстояние впереди. Если оно больше 30 сантиметров, то продолжаем двигаться вперед, иначе:

  • останавливаем двигатели
  • поворачиваем сервопривод на углы от 0 до 180 градусов с шагом в 15 градусов и измеряем расстояния на этих углах
  • заносим полученные значения в массив
  • поворачиваем сервопривод на угол 90 градусов (прямо)
  • ищем в массиве позицию с максимальным значением данных
  • если это значение меньше 30 сантиметров, то едем назад
  • если это значение больше 30 сантиметров, то проверяем какому углу поворота сервопривода оно соответствует и в зависимости от этого поворачиваем влево или вправо

Можно еще сделать проверку на большее расстояние впереди. Тогда можно будет не останавливать двигатели, а использовать плавный поворот.

Скетч реализации алгоритма объезда препятствий

#include <AFMotor.h> // Подключаем библиотеку для управления двигателями
#include <Servo.h>   // Подключаем библиотеку для сервоприводов
#include <SoftwareSerial.h> // Подключаем библиотеку для работы с Serial через дискретные порты

//Создаем объекты для двигателей
AF_DCMotor motor1(1); //канал М1 на Motor Shield — задний левый
AF_DCMotor motor2(2); //канал М2 на Motor Shield — задний правый
AF_DCMotor motor3(3); //канал М3 на Motor Shield — передний левый
AF_DCMotor motor4(4); //канал М4 на Motor Shield — передний правый
// Создаем объект для сервопривода
Servo vservo;
// Прописываем пины используемые модулем Bluetooth
SoftwareSerial BTSerial(50, 51); // RX, TX
// Создаем переменную для команд Bluetooth
char vcmd;
// Создаем переменные для запоминания скорости левых и правых двигателей
int vspdL, vspdR;
/* Создаем переменную, на значение которой будет уменьшаться скорость при плавных поворотах.
Текущая скорость должна быть больше этого значения.  В противном случае двигатели со стороны направления поворота просто не будут вращаться */
const int vspd = 200;
// Заносим в массив пины, к которым подключены светодиоды
const int vledpins[6]={
22,23,24,25,26,27};
// Создаем переменную для сохранения режима работы
int vmode;
// Создаем переменную для сохранения предыдущего режима работы
int vmodeprev = -1;
// Заносим в массив пины, к которым подключены кнопки
const int vbtn[2]={
28,29};
// Массив для хранения углов поворота сервопривода (шаг 15 градусов)
const int vservo_array[13]={
0,15,30,45,60,75,90,105,120,135,150,165,180};
// Массив для хранения данных о расстоянии под различными углами поворота сервопривода
int vHC_SR04_array[13];
// Пины, используемые ультразвуковым дальномером
const int vTrig = 31;
const int vEcho = 30;
// Переменные, для хранения данных с дальномера
unsigned int vtime_us=0;
unsigned int vdistance_sm=0;
// Минимальное расстояние в сантиметрах, при котором нужно искать новый маршрут движения
const int vmindistance = 30;
// Переменная для циклов перебора значения массивов vservo_array и vHC_SR04_array
int vservo_int;
// Переменные для цикла поиска максимального значения в массивах
int vmaxarrayindex_int;
int vmaxarrayvalue_int;

void setup() {
// Устанавливаем скорость передачи данных по Bluetooth
BTSerial.begin(9600);
// Устанавливаем скорость передачи данных по кабелю
Serial.begin(9600);
// Выбираем пин к которому подключен сервопривод
vservo.attach(9); // или 10, если воткнули в крайний разъём
// Поворачиваем сервопривод в положение 90 градусов при каждом включении
vservo.write(90);
// Устанавливаем максимальную скорость вращения двигателей
vspeed(255,255);
/* Устанавливаем все выводы, к которым подключены светодиоды,
в OUTPUT. Зажигаем и гасим светодиоды с интервалом в 0.5 сек
для проверки */
for (vmode = 0; vmode < 6; vmode = vmode + 1) {
pinMode(vledpins[vmode], OUTPUT);
digitalWrite(vledpins[vmode], HIGH);
delay (500);
digitalWrite(vledpins[vmode], LOW);
}
/* Устанавливаем выводы, к которым подключены кнопки, в INPUT. */
pinMode(vbtn[0], INPUT);
pinMode(vbtn[1], INPUT);
// Устанавливаем значение первого режима работы робота
vmode = 0;
// Устанавливаем значение для пинов, к которым подключен ультразвуковой дальномер
pinMode(vTrig, OUTPUT);
pinMode(vEcho, INPUT);
}

void loop() {
/* Переключение режимов работы робота */
// Кнопка переключения на следующий режим - BTN1
if (digitalRead(vbtn[0]) == HIGH) {
vmode = vmode + 1;
vmodeprev = vmode - 1;
if (vmode > 5) {
vmode = 0;
vmodeprev = 5;
}
vrelease();
delay (500);
}
// Кнопка переключения на предыдущий режим - BTN2
if (digitalRead(vbtn[1]) == HIGH) {
vmode = vmode - 1;
vmodeprev = vmode + 1;
if (vmode < 0) {
vmode = 5;
vmodeprev = 0;
}
vrelease();
delay (500);
}
// Засвечиваем светодиод текущего режима работы
digitalWrite(vledpins[vmode], HIGH);
// Гасим светодиод предыдущего режима работы
if (vmodeprev > -1) {
digitalWrite(vledpins[vmodeprev], LOW);
}
/* Выбор режима работы */
switch (vmode) {
case 0:
// Режим ожидания
break;
case 1:
// Режим работы с использованием ультразвукового дальномера
vultrasoundmode();
break;
case 2:
// Режим
break;
case 3:
// Режим управления через Bluetooth
vbluetoothmode();
break;
case 4:
// Режим
break;
case 5:
// Режим
break;
}
}
/* Режим работы с использованием ультразвукового дальномера */
void vultrasoundmode(){
vservo.write(90);
delay(200);
Serial.print("Now ");
Serial.println(vHC_SR04());
// Если расстояние меньше наименьшего, то
if (vHC_SR04() < vmindistance) {
// Останавливаем двигатели
vrelease();
// Крутим серву измеряя расстояния и занося данные в массив
for (vservo_int = 0; vservo_int < 13; vservo_int = vservo_int + 1) {
vservo.write(vservo_array[vservo_int]);
delay(200);
vHC_SR04_array[vservo_int] = vHC_SR04();
// Выводим данные для отладки
Serial.print(vservo_int);
Serial.print(" ");
Serial.println(vHC_SR04_array[vservo_int]);
}
vservo.write(90);
delay(500);
// Поиск в массиве позиции с максимальным значением
vmaxarrayindex_int = 0;
vmaxarrayvalue_int = 0;
for (vservo_int = 0; vservo_int < 13; vservo_int = vservo_int + 1) {
if (vHC_SR04_array[vservo_int] > vmaxarrayvalue_int) {
vmaxarrayindex_int = vservo_int;
vmaxarrayvalue_int = vHC_SR04_array[vservo_int];
}
}
Serial.print("Max index ");
Serial.println(vmaxarrayindex_int);
// Проверка - если максимальное значение массива меньше минимального расстояния, то едем назад
if (vHC_SR04_array[vmaxarrayindex_int] < vmindistance) {
vbackward();
delay(500);
}
/* Проверка - если индекс максимального значения массива меньше 6 то поворачиваем вправо,
иначе влево */
if (vmaxarrayindex_int < 6) {
vright();
delay(500);
}
else
{
vleft();
delay(500);
}
}
else
{
// Едем прямо
vforward();
}
}

/* Режим управления через Bluetooth */
void vbluetoothmode() {
// Если есть данные с Bluetooth
if (BTSerial.available())
{
/* Читаем команды и заносим их в переменную.
(char) преобразует код символа команды в символ */
vcmd = (char)BTSerial.read();
// Отправляем команду в порт, чтобы можно было их проверить в "Мониторе порта"
Serial.println(vcmd);

// Вперед
if (vcmd == 'F') {
vforward();
}
// Назад
if (vcmd == 'B')
{
vbackward();
}
// Влево
if (vcmd == 'L')
{
vleft();
}
// Вправо
if (vcmd == 'R')
{
vright();
}
// Прямо и влево
if (vcmd == 'G')
{
vforwardleft();
}
// Прямо и вправо
if (vcmd == 'I')
{
vforwardright();
}
// Назад и влево
if (vcmd == 'H')
{
vbackwardleft();
}
// Назад и вправо
if (vcmd == 'J')
{
vbackwardright();
}
// Стоп
if (vcmd == 'S')
{
vrelease();
}
// Скорость 0%
if (vcmd == '0')
{
vspeed(0,0);
}
// Скорость 10%
if (vcmd == '1')
{
vspeed(25,25);
}
// Скорость 20%
if (vcmd == '2')
{
vspeed(50,50);
}
// Скорость 30%
if (vcmd == '3')
{
vspeed(75,75);
}
// Скорость 40%
if (vcmd == '4')
{
vspeed(100,100);
}
// Скорость 50%
if (vcmd == '5')
{
vspeed(125,125);
}
// Скорость 60%
if (vcmd == '6')
{
vspeed(150,150);
}
// Скорость 70%
if (vcmd == '7')
{
vspeed(175,175);
}
// Скорость 80%
if (vcmd == '8')
{
vspeed(200,200);
}
// Скорость 90%
if (vcmd == '9')
{
vspeed(225,225);
}
// Скорость 100%
if (vcmd == 'q')
{
vspeed(255,255);
}
}
}

/* Функция определения расстояния с дальномера */
int vHC_SR04() {
digitalWrite(vTrig, HIGH); // Подаем сигнал на выход микроконтроллера
delayMicroseconds(10); // Удерживаем 10 микросекунд
digitalWrite(vTrig, LOW); // Затем убираем
vtime_us=pulseIn(vEcho, HIGH); // Замеряем длину импульса
vdistance_sm=vtime_us/58; // Пересчитываем в сантиметры
return vdistance_sm; // Возвращаем значение
}

/* Функции управления двигателями */

// Вперед
void vforward() {
vspeed(vspdL,vspdR);
vforwardRL();
}

// Вперед для RL
void vforwardRL() {
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
}

// Назад
void vbackward() {
vspeed(vspdL,vspdR);
vbackwardRL();
}

// Назад для RL
void vbackwardRL() {
motor1.run(BACKWARD);
motor2.run(BACKWARD);
motor3.run(BACKWARD);
motor4.run(BACKWARD);
}

// Влево
void vleft() {
vspeed(vspdL,vspdR);
motor1.run(BACKWARD);
motor2.run(FORWARD);
motor3.run(BACKWARD);
motor4.run(FORWARD);
}

// Вправо
void vright() {
vspeed(vspdL,vspdR);
motor1.run(FORWARD);
motor2.run(BACKWARD);
motor3.run(FORWARD);
motor4.run(BACKWARD);
}

// Вперед и влево
void vforwardleft() {
if (vspdL > vspd) {
vspeed(vspdL-vspd,vspdR);
}
else
{
vspeed(0,vspdR);
}
vforwardRL();
}

// Вперед и вправо
void vforwardright() {
if (vspdR > vspd) {
vspeed(vspdL,vspdR-vspd);
}
else
{
vspeed(vspdL,0);
}
vforwardRL();
}

// Назад и влево
void vbackwardleft() {
if (vspdL > vspd) {
vspeed(vspdL-vspd,vspdR);
}
else
{
vspeed(0,vspdR);
}
vbackwardRL();
}

// Назад и вправо
void vbackwardright() {
if (vspdR > vspd) {
vspeed(vspdL,vspdR-vspd);
}
else
{
vspeed(vspdL,0);
}
vbackwardRL();
}

// Стоп
void vrelease(){
motor1.run(RELEASE);
motor2.run(RELEASE);
motor3.run(RELEASE);
motor4.run(RELEASE);
}

// Изменение скорости
void vspeed(int spdL,int spdR){
if (spdL == spdR) {
vspdL=spdL;
vspdR=spdR;
}
motor1.setSpeed(spdL);
motor2.setSpeed(spdR);
motor3.setSpeed(spdL);
motor4.setSpeed(spdR);
}

В строках, на которые будет ругаться компилятор, поменяйте тире на минусы.

Демонстрация робота на Arduino

P.S.

В следующий раз я попробую реализовать алгоритм прохождения лабиринта по правилу правой руки или движение по белой линии.

Присоединяйтесь к нашей группе в Telegram @GeekElectronics
  • keyboard_arrow_downВедроид-мобиль — робот на Arduino — Часть 4. Подключаем ультразвуковой дальномер
    • Автор:
    • Миниатюра: Ведроид-мобиль — робот на Arduino — Часть 4. Подключаем ультразвуковой дальномер
    • Рубрика: Arduino от А до Я
    • Обновлено: 26.12.2017
    • Комментариев: 83
    • Просмотров: 26 403
  • Оцените пожалуйста статью
    1 Star2 Stars3 Stars4 Stars5 Stars
    Загрузка...
  • Поделитесь с друзьями
Geek Electronics

Комментариев: 83

  • Avatar for source
    Вадим:

    Блин, у меня машина живёт своей жизнью, я правда переделал код под РУ машину.

    • Avatar for source
      source:

      может серву запитай отдельно, а то у меня тоже была проблема с нехваткой тока от встроенного в Arduino стабилизатора

      • Avatar for source
        Вадим:

        Не, у меня преобразователь из 7.4 в 6. Всё нормально работало.

      • Avatar for source
        Вадим:

        Хотя да! Наверно дело в питании, потому что у тебя на видео серва быстро крутиться, а у меня slow.

  • Avatar for source
    Александр:

    Полезная статья, спасибо. Разбирался тут в вашем коде. Особенно мне полезно было унать про программную часть использования этого дальнометра (у меня такой же). Всё, что хотел узнать, понял. А конструкцию
    int vHC_SR04() {
    const int vTrig = 31;
    const int vEcho = 30;
    unsigned int vdistance_sm=0;
    unsigned int vtime_us=0;
    digitalWrite(vTrig, HIGH);
    delayMicroseconds(10);
    digitalWrite(vTrig, LOW);
    vtime_us=pulseIn(vEcho, HIGH);
    vdistance_sm=vtime_us/58;
    return vdistance_sm;
    }
    нужно писать каждый раз, когда требуется узнать показания? Понятно, циклы никто не отменял, но это - единственный способ замерить показания?

    • Avatar for source
      source™:

      это функция определения расстояния - написать ее надо только 1 раз
      чтобы ее использовать просто пишите vHC_SR04()
      это ее вызовет в нужном месте и вернет вам результаты измерений

  • Avatar for source
    aleks:

    Мне очень нравиться! Но можно переделать на ардуино уно, на етой порти то не все задействованы, а на уно портов должно хватить.

    • Avatar for source
      source™:

      Поменяйте в скетче номера портов на свои.
      У меня просто нет UNO - сам не могу проверить.

  • Avatar for source
    aleks:

    Окей попробую но токо прийтется шилд купить а то старый згорел почемуто

  • Avatar for source
    Artemka:

    Полезная статья.Спасибо Вам.
    Попробовал Ваш скетч откомпелировать но он выдал вот такие ошибки:
    In file included from sketch_nov28b.ino:3:
    C:\arduino-1.0.2\libraries\SoftwareSerial/SoftwareSerial.h:52: error: conflicting return type specified for 'virtual void SoftwareSerial::write(uint8_t)'
    C:\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:48: error: overriding 'virtual size_t Print::write(uint8_t)'
    Ни как не могу побороть. Не подскажете причину ?
    Использую Arduino IDE 1.0.2.

    • Avatar for source
      source:

      у меня версия 1.0.5
      перепроверил скетч - в строках кода, на которые ругается компилятор замените тире на минусы.

      • Avatar for source
        Artemka:

        Все проверил ошибка осталась, но добавилась еще одна sketch_nov28a.cpp: In function 'void vbluetoothmode()':
        sketch_nov28a:193: error: 'class SoftwareSerial' has no member named 'available'

  • Avatar for source
    Денис:

    Было бы интересно реализовать конструкцию с 2 дальномерами, где первый сканирует сектор спереди, а другой постоянно отмеряет расстояние до препятствия по линии движения.

  • Avatar for source
    денис:

    а возможно сделать чтоб робот сам переключался между режимами например потерял соединение с блютуз и переключился на датчик?

  • Avatar for source
    илья:

    А можешь пожалуйста скинуть код с режимом объезжать все препятствия только без bluetooth, сервопривода, светодиодов.

    • Avatar for source
      source™:

      К сожалению нет. Без сервопривода никак. У меня поиск проезда завязан на измерении расстояний по сторонам.

  • Avatar for source
    makc:

    Было бы прикольно, если бы игрушка составляла что-то на подобии карты, где можно передвигаться (примерно как у роботов-пылесосов).

  • Avatar for source
    Олег:

    Здравствуйте! Подскажите будете реализовывать следующие функции
    Возможность движения по загруженному GPS треку
    Запись маршрута движения в файл

    • Avatar for source
      source:

      Пока не готов вам ответить. Думал об этом, но пока отвлекся на другой проект.

  • Avatar for source
    Александр:

    Добрый день!
    Очень понравилась Ваша статья, собрал машинку по аналогии Вашей, только с дальномером, без bluetooth. Из Вашего кода убрал всё что относится к bluetooth, выбору режимов, светодиодам и т.п., проверку скетч проходит, но машинка не едет! Если Вам не сложно, можете глянуть мой код, что-то я упустил наверно? Спасибо!
    #include
    #include
    #include

    //Создаем объекты для двигателей
    AF_DCMotor motor1(1); //канал М1 на Motor Shield — задний левый
    AF_DCMotor motor2(2); //канал М2 на Motor Shield — задний правый
    AF_DCMotor motor3(3); //канал М3 на Motor Shield — передний левый
    AF_DCMotor motor4(4); //канал М4 на Motor Shield — передний правый
    // Создаем объект для сервопривода
    Servo vservo;
    // Создаем переменные для запоминания скорости левых и правых двигателей
    int vspdL, vspdR;
    /* Создаем переменную, на значение которой будет уменьшаться скорость при плавных поворотах.
    Текущая скорость должна быть больше этого значения. В противном случае двигатели со стороны направления поворота просто не будут вращаться */
    const int vspd = 200;
    // Массив для хранения углов поворота сервопривода (шаг 15 градусов)
    const int vservo_array[13]={
    0,15,30,45,60,75,90,105,120,135,150,165,180};
    // Массив для хранения данных о расстоянии под различными углами поворота сервопривода
    int vHC_SR04_array[13];
    // Пины, используемые ультразвуковым дальномером
    const int vTrig = 31;
    const int vEcho = 30;
    // Переменные, для хранения данных с дальномера
    unsigned int vtime_us=0;
    unsigned int vdistance_sm=0;
    // Минимальное расстояние в сантиметрах, при котором нужно искать новый маршрут движения
    const int vmindistance = 30;
    // Переменная для циклов перебора значения массивов vservo_array и vHC_SR04_array
    int vservo_int;
    // Переменные для цикла поиска максимального значения в массивах
    int vmaxarrayindex_int;
    int vmaxarrayvalue_int;

    void setup() {
    // Устанавливаем скорость передачи данных по кабелю
    Serial.begin(9600);
    // Выбираем пин к которому подключен сервопривод
    vservo.attach(9); // или 10, если воткнули в крайний разъём
    // Поворачиваем сервопривод в положение 90 градусов при каждом включении
    vservo.write(90);
    // Устанавливаем максимальную скорость вращения двигателей
    vspeed(255,255);
    // Устанавливаем значение для пинов, к которым подключен ультразвуковой дальномер
    pinMode(vTrig, OUTPUT);
    pinMode(vEcho, INPUT);
    }
    void loop() {}
    /* Режим работы с использованием ультразвукового дальномера */
    void vultrasoundmode(){
    vservo.write(90);
    delay(200);
    Serial.print("Now ");
    Serial.println(vHC_SR04());
    // Если расстояние меньше наименьшего, то
    if (vHC_SR04() < vmindistance) {
    // Останавливаем двигатели
    vrelease();
    // Крутим серву измеряя расстояния и занося данные в массив
    for (vservo_int = 0; vservo_int < 13; vservo_int = vservo_int + 1) {
    vservo.write(vservo_array[vservo_int]);
    delay(200);
    vHC_SR04_array[vservo_int] = vHC_SR04();
    // Выводим данные для отладки
    Serial.print(vservo_int);
    Serial.print(" ");
    Serial.println(vHC_SR04_array[vservo_int]);
    }
    vservo.write(90);
    delay(500);
    // Поиск в массиве позиции с максимальным значением
    vmaxarrayindex_int = 0;
    vmaxarrayvalue_int = 0;
    for (vservo_int = 0; vservo_int vmaxarrayvalue_int) {
    vmaxarrayindex_int = vservo_int;
    vmaxarrayvalue_int = vHC_SR04_array[vservo_int];
    }
    }
    Serial.print("Max index ");
    Serial.println(vmaxarrayindex_int);
    // Проверка - если максимальное значение массива меньше минимального расстояния, то едем назад
    if (vHC_SR04_array[vmaxarrayindex_int] < vmindistance) {
    vbackward();
    delay(500);
    }
    /* Проверка - если индекс максимального значения массива меньше 6 то поворачиваем вправо,
    иначе влево */
    if (vmaxarrayindex_int vspd) {
    vspeed(vspdL-vspd,vspdR);
    }
    else
    {
    vspeed(0,vspdR);
    }
    vforwardRL();
    }

    // Вперед и вправо
    void vforwardright() {
    if (vspdR > vspd) {
    vspeed(vspdL,vspdR-vspd);
    }
    else
    {
    vspeed(vspdL,0);
    }
    vforwardRL();
    }

    // Назад и влево
    void vbackwardleft() {
    if (vspdL > vspd) {
    vspeed(vspdL-vspd,vspdR);
    }
    else
    {
    vspeed(0,vspdR);
    }
    vbackwardRL();
    }

    // Назад и вправо
    void vbackwardright() {
    if (vspdR > vspd) {
    vspeed(vspdL,vspdR-vspd);
    }
    else
    {
    vspeed(vspdL,0);
    }
    vbackwardRL();
    }

    // Стоп
    void vrelease(){
    motor1.run(RELEASE);
    motor2.run(RELEASE);
    motor3.run(RELEASE);
    motor4.run(RELEASE);
    }

    // Изменение скорости
    void vspeed(int spdL,int spdR){
    if (spdL == spdR) {
    vspdL=spdL;
    vspdR=spdR;
    }
    motor1.setSpeed(spdL);
    motor2.setSpeed(spdR);
    motor3.setSpeed(spdL);
    motor4.setSpeed(spdR);
    }

    • Avatar for source
      source:

      Свяжитесь со мной через странику Контакты. Скину свой скайп или асю - там и решим проблему

      • Avatar for source
        Вячеслав:

        Пожалуйста, выложите скетч только с дальномером, без bluetooth и светодиодов.

    • Avatar for source
      minotarius:

      У Вас в функции loop() {} в фигурных скобках пустой оператор поэтому программа ничего и не делает полезного.

      • Avatar for source
        Вячеслав:

        Если убрать фигурные скобки то это проблему не решает

    • Avatar for source
      Вячеслав:

      тоже столкнулись с такой проблемой, как ее решили, что нужно исправить в коде?

  • Avatar for source
    Alex:

    Не могли бы вы скинуть скетч без модуля Bluetooth, выбора режимов, светодиодов. Только с дальномером, реализовав алгоритм объезда препятствий.

  • Avatar for source
    Андрей:

    Классно сделано. Подскажите, пожалуйста чем вы питаете проект? Если можно подскажите как лучше питать: все через шилд, или дуину отдельно шилд отдельно?

    • Avatar for source
      source™:

      через motor shield. встроенные в ардуино стабилизатор не потянет сервопривод

    • Avatar for source
      source™:

      проект запитывал от 4-х аккумуляторов 18650, подключенных параллельными парами последовательно
      хватил и двух, соединенных последовательно

        • Avatar for source
          source™:

          http://g.zeos.in/?q=18650%20%D0%B0%D0%BA%D0%BA%D1%83%D0%BC%D1%83%D0%BB%D1%8F%D1%82%D0%BE%D1%80

          • Avatar for source
            source™:

            можно наковырять из старого аккумулятора ноутбука

          • Avatar for source
            Андрей:

            Т.Е. можно разбить старую батарею от ноутбука? А можно их заряжать обычными зарядным для аккумуляторов?

          • Avatar for source
            source™:

            я у китайцев отдельную зарядку купил
            если "обычная" зарядка имеет редим для зарядки этих, то почему бы и нет
            у них просто напряжение выше

          • Avatar for source
            Андрей:

            Спасибо, очень полезная информация. Обязательно про пощусь в соц сетях о вашем сайте. Расковырял, а вот как зарядить ума не приложу?

          • Avatar for source
            Андрей:

            Если не достал уже, подскажите еще, если на батарейке нет заряда (вольтметр на тестере показывает +/- 0) их еще можно оживлять или это все им уже. Три были с зарядом в 1В, а 6 вот таких. Батарея год или два лежала в гараже.)))

          • Avatar for source
            source™:

            скорее всего им кранты

      • Avatar for source
        Андрей:

        А можете чуть по подробнее как это: "от 4-х аккумуляторов , подключенных параллельными парами последовательно". Как это исполнить?

          • Avatar for source
            Андрей:

            Ааа. Понял. Параллельность, для того чтобы увеличить емкость. А последовательность дает из 3,7*2=7,4V Правильно я понял? )))

  • Avatar for source
    Андрей:

    Подскажите еще, если можно, обязательно ли ставить сопротивление для светодиодов и для чего это делается.

    • Avatar for source
      source™:

      обязательно
      это делитель напряжения
      без него тог потребления светодиодов будет большим - другими словами они будут подкорачивать питание
      еще без резистора на них будет идти большее напряжение чем надо.

      посмотрите все видеоуроки по адруино у меня на блоге - многие вопросы отпадут

        • Avatar for source
          source™:

          я в статье писал, что 220 Ом
          при 1 кОм может и не загореться, но попробуйте

          • Avatar for source
            Андрей:

            Спасибо огромное за помощь! За сегодня очень продвинулся. Я как и обещался пропостился.)

          • Avatar for source
            Андрей:

            Эти уроки я вроде смотрел, вот не все еще отложилось) Все равно спасибо.

  • Avatar for source
    Nikita:

    Подскажите, почему куски скетча для управления через блютуз и с помощью дальномера вынесены из void loop? Их можно не выносить?

    • Avatar for source
      source™:

      я их оформил как отдельные функции
      если оставить в loop то придется один и тот же код вставлять несколько раз

  • Avatar for source
    Никита:

    Подскажите, пожалуйста, в чем может быть проблема. У меня скетч почти такой же, просто написан под другое приложение и исправлен под uno. Не работает кнопка (не переключает). Причем, если оставить vrelease() и delay, то не компилируется, а если не изменить 0 на 1 в vbtn[0], то не подключается через блютуз. Кнопка только одна, так как для двух у uno не хватает пинов.
    // Кнопка переключения на следующий режим - BTN1
    if (digitalRead(vbtn[0]) == HIGH) {
    vmode = vmode + 1;
    vmodeprev = vmode - 1;
    if (vmode > 5) {
    vmode = 0;
    vmodeprev = 5;
    }
    vrelease();
    delay (500);
    }

  • Avatar for source
    MIIRIK:

    В проге Bluetooth RC Car есть иконки:Свет, стоп сигнал и аварийка, объясните про подключение светодиодов поподробней,пжалста.

  • Avatar for source
    саша:

    а можете сделать точно такую машинку но с двумя моторами,сколько не пытался алгоритм ваш переделать не получается,просто у меня два мотора или может скетч есть,очень нужно

    • Avatar for source
      Miiriik:

      Другой шильд под моторы?на 2 выхода?или этот переделать на 2?

  • Avatar for source
    source™:

    уже сделать ничего не могу - давно ее разобрал так как наигрался

    • Avatar for source
      саша:

      скажи как переключение подключить,тут написано 28 и 29 это переключение,так вот с одной стороны подключить к кнопке а второе к чему что бы режимы переключить не пойму ни как а так всё вроде работает но перерывами потому что не знаю как переключить на блютуз и обратно подскажи,куда делся ты???

  • Avatar for source
    Дара:

    Всем привет! Друзья помогите, я как бы новичок и хочу построить робот на базе ардуино. Такой вопрос: а в какую программу загружать скетч?(как называется прога). На телефон я установил прогу Bluetooth RC controler.

    • Avatar for source
      MIIRIIK:

      Делайте все в соответствии с постом, и у вас все получиться.я все заказал на алиэкспресе (там дешевле), и взял за основу ардуино уно, т.к. если на меге собирать остается очень много свободных портов, но если новичок, сразу попробуйте что нибудь попроще. В проге что вы скачале смотрите на какой пин задействованы свет, стоп сигналы, аварийка, и гудок и просто их добавляете в скетч. удачи!!!
      P/S/ я наигрался на 2-й день

      • Avatar for source
        Алексей:

        Ставь модуль для работы с SD картами. Составляй планы помещения. Вытащи с мышек оптический датчик и сделай распознавание лиц. Сделай в машинке режим следования за хозяином и исследования окружающего пространства. Там много чего накрутить можно. Поставь в него GPS датчик и пусть шурует в заранее заданную точку пространства.
        Собери две машинки и пусть воюют между собой с помощью ИК-передатчиков и приемников. Задач дочерта. Уже месяца три балуюсь.

      • Avatar for source
        саша:

        как переключить режыми к чему подключавть 28 и 29 к кнопке а втроой провод где минус или что?????????????

  • Avatar for source
    Алексей:

    Все собралось, все работает. Но хочу небольшое замечание сделать.
    Зачем было городить кнопки, когда в программе есть возможность включения фар? Включил фары - идет по дальномеру. Отключил - идет по управлению оператора.
    Еще показалась интересной мысль распределения задач на две ардуино уно. Одна чисто под управление движками, вторая с внешней периферией работает. Трех пинов вполне должно хватить для обмены между платами. Выигрыш - в оперативности обработки сигналов за счет параллельной обработки. Если выпускать машинку на улицу, то скорость реакции будет иметь значение. ;)

  • Avatar for source
    саша:

    дайте кто скетч залить для ардуино мега 2560 для двух моторов,поставил драйвер моторов на два колеса и серво привод и дальномер,что бы не сталкивался но тут какие то диоды,кнопки,зачем это мне,мне нужно что бы или сам ехал или через блютуз или вайфай работал на сотовом,потом хочу эту технологию на снегоуборщика поставить самодельного,но пока мелкий не протестирую,ставеть не буду дак вот скетч нужен

    • Avatar for source
      Алексей:

      Кнопки тебе не очень нужны. Просто в блоке "Выбор режима работы" перед свичем принудительно присвой переменной vmode=3. Должно получиться так.
      /* Выбор режима работы */
      vmode=3;
      switch (vmode) {
      case 0:
      // Режим ожидания
      break;
      case 1:
      // Режим работы с использованием ультразвукового дальномера
      vultrasoundmode();
      break;
      case 2:
      // Режим
      break;
      case 3:
      // Режим управления через Bluetooth
      vbluetoothmode();
      break;
      case 4:
      // Режим
      break;
      case 5:
      // Режим
      break;
      }

      А по двум движкам - не ленимся, батенька, ручками блокируем код, относящийся к отсутствующим двигателя. Хотя, если у тебя мотор-шилд такой же, то можно ничего не менять.
      А как проблему с питанием и гидроизоляцией решал?

      • Avatar for source
        саша:

        значит всё тоже самое залить и просто равно 3 поставить,так?просто я скетч залил,дак он что минуту чего то ждёт а потом серво в лево и в право и дальномер пробивает зону,ну что бы не столкнуться потом пару раз проедет и всё,я думаю из за этих кнопок,ну я попробую залить и так сделать,а что про питание писали,вы про снегоуборщик,если про него,так есть китайский регулятор напруги,но он мне даже не нужен потому что я решил использовать контроллеры от электро велосипеда но минус один,моторы крутит прямо,а назад не поедет,в силу недостатка денег всё движется пока медленно и мой робот снегоуборщик на шести колёсах пока кроме рамы и моторов и контроллеров не ставил ещё,правда было маленькое испытание,едет но пока с трудом на всё нужны деньги и время,чего мне больше всего не хватает сейчас

      • Avatar for source
        саша:

        как эти кнопки подключить 28 и 29,если не нужны то через что тогда подключать через блютуз получиться?

  • Avatar for source
    саша:

    а ещё хотел спросить а как ещё добавить,что бы ехал к примеру до забора потом разворачивался и рядом где ехал только на пол метра дальше обратно ехал,потом опять на два метра от угла и так туда сюда но отдалялся и чистил снег,может камеру поставить или где раздобыть прогу робота пулисоса но что бы карту делал местности и потом ездил да убирал,была бы такая система я бы давно поставил а пока давольствуюсь тем что есть,да и проще всего

  • Avatar for source
    саша:

    я одно не понял,если в свиче поставить 3 то как переключатся на то,что бы с сотового можно было переключить на автономного,то есть что бы сам ездил и обратно на ручное управление,если поставлю Кнопки тебе не очень нужны. Просто в блоке "Выбор режима работы" перед свичем принудительно присвой переменной vmode=3. Должно получиться так.
    /* Выбор режима работы */
    vmode=3;
    то где кнопка через блютуз будет на переключение на блютуз и обратно на автомат так скажем мне нужно что бы два в одном было и сам ездил и через блютуз переключил и он поехал,видосов много смотрел но то ездит сам или по блютуз но отдельно,мне всё вместе нужно на ардуино мега 2560 и через этот мотор шилд

  • Avatar for source
    Виталий:

    Парни мне одному так кажеться или он местами
    8 - GND - к GND Arduino Mega 2560
    9 - +5 V - к +5 V Arduino Mega 2560
    попутал?

        • Avatar for source
          саша:

          да вроде проблем у меня нету,как только переключить режимы,у меня есть другие скетчи но там всё отдельно,если едет автономно то не переключишь через блютуз,а есть и с блютуз но не автономно но там за то можно свет включить передних фар и задних и аварийку,но мне нужно что бы ещё переключить можно на другой режим,а здесь ты разобрался с кнопками 28 и 29,как переключить???куда проводки тыркнуть что бы режим переключился,а то без диодов и кнопок потрогаешь он пол минуты сам поездит и станет,а как переключить на блютуз тыркал в разные разьёмы так и не переключился на блютуз бывает через блютуз дёрнеться,и резко в автономный режим переключаеться

          • Avatar for source
            Виталий:

            я же тебе говорю скорее всего разъемы перепутаны.

  • Avatar for source
    саша:

    да какая разница я другой скетч выложил по блютуз правда но пока и так сойдёт

  • Avatar for source
    саша:

    #include
    #include

    int ledPin1 = 22; // передние фары
    int ledPin2 = 24; // передние фары
    int ledPin3 = 34; // задние фары
    int ledPin4 = 35; // задние фары
    int ledPin5 = A8; // клаксон
    int ledPin6 = A9; // питание для клаксона
    //Создаем объекты для двигателей
    AF_DCMotor motor1(1); //канал М1 на Motor Shield — задний левый
    AF_DCMotor motor2(2); //канал М2 на Motor Shield — задний правый
    AF_DCMotor motor3(3); //канал М3 на Motor Shield — передний левый
    AF_DCMotor motor4(4); //канал М4 на Motor Shield — передний правый

    //Время мигания Аварийки
    int blinkTime = 15; //частота мигания
    int leftTime = 0;
    boolean signalOn = LOW;
    boolean avaOn = LOW;

    SoftwareSerial BTSerial(50, 51); // RX, TX

    // Создаем переменную для команд Bluetooth
    char vcmd;
    // Создаем переменные для запоминания скорости двигателей
    int vspdL, vspdR;
    /* Создаем переменную, на значение которой будет уменьшаться скорость при плавных поворотах.
    Текущая скорость должна быть больше этого значения. В противном случае двигатели со стороны направления поворота просто не будут вращаться */
    int vspd = 200;

    void setup() {
    pinMode(ledPin1, OUTPUT);
    pinMode(ledPin2, OUTPUT);
    pinMode(ledPin3, OUTPUT);
    pinMode(ledPin4, OUTPUT);
    pinMode(ledPin5, OUTPUT);
    pinMode(ledPin6, OUTPUT);
    digitalWrite(ledPin6, HIGH);
    // Устанавливаем скорость передачи данных по Bluetooth
    BTSerial.begin(9600);
    // Устанавливаем скорость передачи данных по кабелю
    Serial.begin(9600);
    // Устанавливаем максимальную скорость вращения двигателей
    vspeed(255,255);
    }

    void loop() {
    // Если есть данные
    if (BTSerial.available())
    {
    // Читаем команды и заносим их в переменную. char преобразует код символа команды в символ
    vcmd = (char)BTSerial.read();
    // Отправляем команду в порт, чтобы можно было их проверить в "Мониторе порта"
    //Serial.println(vcmd);

    // Передние фары ВКЛ
    if (vcmd == 'W') {
    digitalWrite(ledPin1, HIGH);
    digitalWrite(ledPin2, HIGH);
    }

    // Передние фары ВЫКЛ
    if (vcmd == 'w') {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    }

    // Задние фары ВКЛ
    if (vcmd == 'U') {
    digitalWrite(ledPin3, HIGH);
    digitalWrite(ledPin4, HIGH);
    }

    // Задние фары ВЫКЛ
    if (vcmd == 'u') {
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin4, LOW);
    }

    // Аварийка ВКЛ
    if (vcmd == 'X') {
    avaOn = HIGH;
    }

    // Аварийка ВЫКЛ
    if (vcmd == 'x') {
    avaOn = LOW;
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin4, LOW);
    }

    if (vcmd != 'S') {
    Serial.println(vcmd);
    }

    if (avaOn) {
    if (leftTime == 0) {
    leftTime = blinkTime;
    signalOn = !signalOn;
    }
    Serial.print("leftTime = ");
    Serial.println(leftTime);

    if (signalOn) {
    digitalWrite(ledPin1, HIGH);
    digitalWrite(ledPin2, HIGH);
    digitalWrite(ledPin3, HIGH);
    digitalWrite(ledPin4, HIGH);
    delay(1);
    leftTime = leftTime - 1;
    }
    else
    {
    digitalWrite(ledPin1, LOW);
    digitalWrite(ledPin2, LOW);
    digitalWrite(ledPin3, LOW);
    digitalWrite(ledPin4, LOW);
    delay(1);
    leftTime = leftTime - 1;
    }

    } //закончилась Аварийка

    // Клаксон ВКЛ
    if (vcmd == 'V') {
    analogWrite(ledPin5, 200);
    }

    // Клаксон ВЫКЛ
    if (vcmd == 'v') {
    analogWrite(ledPin5, LOW);
    }

    // Вперед
    if (vcmd == 'F') {
    vforward();
    }
    // Назад
    if (vcmd == 'B')
    {
    vbackward();
    }
    // Влево
    if (vcmd == 'L')
    {
    vleft();
    }
    // Вправо
    if (vcmd == 'R')
    {
    vright();
    }
    // Прямо и влево
    if (vcmd == 'G')
    {
    vforwardleft();
    }
    // Прямо и вправо
    if (vcmd == 'I')
    {
    vforwardright();
    }
    // Назад и влево
    if (vcmd == 'H')
    {
    vbackwardleft();
    }
    // Назад и вправо
    if (vcmd == 'J')
    {
    vbackwardright();
    }
    // Стоп
    if (vcmd == 'S')
    {
    vrelease();
    }
    // Скорость 0%
    if (vcmd == '0')
    {
    vspeed(0,0);
    }
    // Скорость 10%
    if (vcmd == '1')
    {
    vspeed(25,25);
    }
    // Скорость 20%
    if (vcmd == '2')
    {
    vspeed(50,50);
    }
    // Скорость 30%
    if (vcmd == '3')
    {
    vspeed(75,75);
    }
    // Скорость 40%
    if (vcmd == '4')
    {
    vspeed(100,100);
    }
    // Скорость 50%
    if (vcmd == '5')
    {
    vspeed(125,125);
    }
    // Скорость 60%
    if (vcmd == '6')
    {
    vspeed(150,150);
    }
    // Скорость 70%
    if (vcmd == '7')
    {
    vspeed(175,175);
    }
    // Скорость 80%
    if (vcmd == '8')
    {
    vspeed(200,200);
    }
    // Скорость 90%
    if (vcmd == '9')
    {
    vspeed(225,225);
    }
    // Скорость 100%
    if (vcmd == 'q')
    {
    vspeed(255,255);
    }
    }
    }

    // Вперед
    void vforward() {
    vspeed(vspdL,vspdR);
    vforwardRL();
    }

    // Вперед для RL
    void vforwardRL() {
    motor1.run(FORWARD);
    motor2.run(FORWARD);
    motor3.run(FORWARD);
    motor4.run(FORWARD);
    }

    // Назад
    void vbackward() {
    vspeed(vspdL,vspdR);
    vbackwardRL();
    }

    // Назад для RL
    void vbackwardRL() {
    motor1.run(BACKWARD);
    motor2.run(BACKWARD);
    motor3.run(BACKWARD);
    motor4.run(BACKWARD);
    }

    // Влево
    void vleft() {
    vspeed(vspdL,vspdR);
    motor1.run(BACKWARD);
    motor2.run(FORWARD);
    motor3.run(BACKWARD);
    motor4.run(FORWARD);
    }

    // Вправо
    void vright() {
    vspeed(vspdL,vspdR);
    motor1.run(FORWARD);
    motor2.run(BACKWARD);
    motor3.run(FORWARD);
    motor4.run(BACKWARD);
    }

    // Вперед и влево
    void vforwardleft() {
    if (vspdL > vspd) {
    vspeed(vspdL-vspd,vspdR);
    }
    else
    {
    vspeed(0,vspdR);
    }
    vforwardRL();
    }

    // Вперед и вправо
    void vforwardright() {
    if (vspdR > vspd) {
    vspeed(vspdL,vspdR-vspd);
    }
    else
    {
    vspeed(vspdL,0);
    }
    vforwardRL();
    }

    // Назад и влево
    void vbackwardleft() {
    if (vspdL > vspd) {
    vspeed(vspdL-vspd,vspdR);
    }
    else
    {
    vspeed(0,vspdR);
    }
    vbackwardRL();
    }

    // Назад и вправо
    void vbackwardright() {
    if (vspdR > vspd) {
    vspeed(vspdL,vspdR-vspd);
    }
    else
    {
    vspeed(vspdL,0);
    }
    vbackwardRL();
    }

    // Стоп
    void vrelease(){
    motor1.run(RELEASE);
    motor2.run(RELEASE);
    motor3.run(RELEASE);
    motor4.run(RELEASE);
    }

    // Изменение скорости
    void vspeed(int spdL,int spdR){
    if (spdL == spdR) {
    vspdL=spdL;
    vspdR=spdR;
    }
    motor1.setSpeed(spdL);
    motor2.setSpeed(spdR);
    motor3.setSpeed(spdL);
    motor4.setSpeed(spdR);
    }

Добавить комментарий

arrow_upward