В этой статье я опишу процесс создания шилда управления роботом, подключение ультразвукового дальномера и реализацию алгоритма объезда препятствий. На выходе у нас должен получиться полностью автономный робот.
А прошлой статье я описывал процесс реализации управления роботом по Bluetooth через смартфон на Android. Это был первый режим работы робота. После этой статьи у нас появится второй режим. В будущем я планирую добавить еще несколько.
Создание шилда управления роботом
Для переключения между различными режимами работы я решил сделать отдельный шилд. В прошлый раз я уже использовал Proto Shield. Сегодня я его немного модернизирую под свои потребности.
Для этого нам понадобятся следующие детали:
- Светодиоды - 7 штук
- Кнопки - 3 штуки
- Резисторы на 220 Ом - 6 штук
- Резисторы на 10 кОм - 2 штуки
- Перемычки - 5 штук
- Разъём PBS (мама) на 16 контактов - 1 штука
- Миниатюрная макетная плата - 1 штука
Все компоненты запаиваем на Proto Shield по указанной схеме (вид со стороны деталей):
Размещение элементов на плате:
В левом нижнем углу я вывел кнопку RESET. Она замыкает выводы RESET и GND. В левом верхнем - разъем подключения сервоприводов. Вверху светодиод с 13 дискретного вывода. Справа 2 кнопки переключения режимов (след / пред).
Каждая кнопка подтянута к земле резистором на 10 кОм.
Далее размещены 6 светодиодов, которые подключены к панельке контактов через резисторы на 220 Ом.
Светодиоды будут служить индикаторами режимов работы робота.
Для разводки дополнительных модулей, я еще решил добавить в шилд управления миниатюрную макетную плату.
Подключение шилда управления роботом
Подключим провода к разъему на 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
Подключение ультразвукового дальномера HC-SR04
Процесс подключения ультразвукового дальномера HC-SR04 к Arduino и работу с ним я описывал ранее. В тонкости в этот раз вдаваться не буду, а лучше подробно распишу как я его закрепил на сервоприводе.
Для создания крепления под ультразвуковой дальномер HC-SR04 я использовал кусок платы от Proto Shield и панельку контактов.
Откусил от панельки контактов две части по 4 контакта и запаял их на плату параллельно.
Перед подключением дальномера я сперва “раскорячил” его контакты, чтобы они плотно держались в разъеме.
Проковырял в плате дырку под болт.
Закрепил модуль на сервоприводе.
В результате у меня получился такой девайс.
Осталось только подключить провода к контактной панельке на плате дальномера и завести их на контакты 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.
В следующий раз я попробую реализовать алгоритм прохождения лабиринта по правилу правой руки или движение по белой линии.
Кода нет =(
уже есть
Блин, у меня машина живёт своей жизнью, я правда переделал код под РУ машину.
может серву запитай отдельно, а то у меня тоже была проблема с нехваткой тока от встроенного в Arduino стабилизатора
Не, у меня преобразователь из 7.4 в 6. Всё нормально работало.
Хотя да! Наверно дело в питании, потому что у тебя на видео серва быстро крутиться, а у меня slow.
Полезная статья, спасибо. Разбирался тут в вашем коде. Особенно мне полезно было унать про программную часть использования этого дальнометра (у меня такой же). Всё, что хотел узнать, понял. А конструкцию
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;
}
нужно писать каждый раз, когда требуется узнать показания? Понятно, циклы никто не отменял, но это - единственный способ замерить показания?
это функция определения расстояния - написать ее надо только 1 раз
чтобы ее использовать просто пишите vHC_SR04()
это ее вызовет в нужном месте и вернет вам результаты измерений
Понял. Спасибо.
Мне очень нравиться! Но можно переделать на ардуино уно, на етой порти то не все задействованы, а на уно портов должно хватить.
Поменяйте в скетче номера портов на свои.
У меня просто нет UNO - сам не могу проверить.
Окей попробую но токо прийтется шилд купить а то старый згорел почемуто
Спасибо!
Полезная статья.Спасибо Вам.
Попробовал Ваш скетч откомпелировать но он выдал вот такие ошибки:
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.
у меня версия 1.0.5
перепроверил скетч - в строках кода, на которые ругается компилятор замените тире на минусы.
Все проверил ошибка осталась, но добавилась еще одна sketch_nov28a.cpp: In function 'void vbluetoothmode()':
sketch_nov28a:193: error: 'class SoftwareSerial' has no member named 'available'
Было бы интересно реализовать конструкцию с 2 дальномерами, где первый сканирует сектор спереди, а другой постоянно отмеряет расстояние до препятствия по линии движения.
а возможно сделать чтоб робот сам переключался между режимами например потерял соединение с блютуз и переключился на датчик?
Хорошая идея. Благодарю за подсказку.
А можешь пожалуйста скинуть код с режимом объезжать все препятствия только без bluetooth, сервопривода, светодиодов.
К сожалению нет. Без сервопривода никак. У меня поиск проезда завязан на измерении расстояний по сторонам.
Было бы прикольно, если бы игрушка составляла что-то на подобии карты, где можно передвигаться (примерно как у роботов-пылесосов).
Здравствуйте! Подскажите будете реализовывать следующие функции
Возможность движения по загруженному GPS треку
Запись маршрута движения в файл
Пока не готов вам ответить. Думал об этом, но пока отвлекся на другой проект.
Добрый день!
Очень понравилась Ваша статья, собрал машинку по аналогии Вашей, только с дальномером, без 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);
}
Свяжитесь со мной через странику Контакты. Скину свой скайп или асю - там и решим проблему
Пожалуйста, выложите скетч только с дальномером, без bluetooth и светодиодов.
У Вас в функции loop() {} в фигурных скобках пустой оператор поэтому программа ничего и не делает полезного.
Если убрать фигурные скобки то это проблему не решает
Ошибка error: 'vultrasoundmode' was not declared in this scope
тоже столкнулись с такой проблемой, как ее решили, что нужно исправить в коде?
Не могли бы вы скинуть скетч без модуля Bluetooth, выбора режимов, светодиодов. Только с дальномером, реализовав алгоритм объезда препятствий.
Да да и мне тоже пожалуйста!
Классно сделано. Подскажите, пожалуйста чем вы питаете проект? Если можно подскажите как лучше питать: все через шилд, или дуину отдельно шилд отдельно?
через motor shield. встроенные в ардуино стабилизатор не потянет сервопривод
проект запитывал от 4-х аккумуляторов 18650, подключенных параллельными парами последовательно
хватил и двух, соединенных последовательно
Спасибо за ответы. А что означает 18650?
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
можно наковырять из старого аккумулятора ноутбука
Т.Е. можно разбить старую батарею от ноутбука? А можно их заряжать обычными зарядным для аккумуляторов?
я у китайцев отдельную зарядку купил
если "обычная" зарядка имеет редим для зарядки этих, то почему бы и нет
у них просто напряжение выше
Спасибо, очень полезная информация. Обязательно про пощусь в соц сетях о вашем сайте. Расковырял, а вот как зарядить ума не приложу?
Если не достал уже, подскажите еще, если на батарейке нет заряда (вольтметр на тестере показывает +/- 0) их еще можно оживлять или это все им уже. Три были с зарядом в 1В, а 6 вот таких. Батарея год или два лежала в гараже.)))
скорее всего им кранты
А можете чуть по подробнее как это: "от 4-х аккумуляторов , подключенных параллельными парами последовательно". Как это исполнить?
Ааа. Понял. Параллельность, для того чтобы увеличить емкость. А последовательность дает из 3,7*2=7,4V Правильно я понял? )))
все верно
Подскажите еще, если можно, обязательно ли ставить сопротивление для светодиодов и для чего это делается.
обязательно
это делитель напряжения
без него тог потребления светодиодов будет большим - другими словами они будут подкорачивать питание
еще без резистора на них будет идти большее напряжение чем надо.
посмотрите все видеоуроки по адруино у меня на блоге - многие вопросы отпадут
Если не тоудно, какой ставить 1кОм пойдет?
я в статье писал, что 220 Ом
при 1 кОм может и не загореться, но попробуйте
Как добраться до видео? Заранее спасибо.
https://geekelectronics.org/arduino/videouroki-po-arduino-na-russkom.html
Спасибо огромное за помощь! За сегодня очень продвинулся. Я как и обещался пропостился.)
Эти уроки я вроде смотрел, вот не все еще отложилось) Все равно спасибо.
Подскажите, почему куски скетча для управления через блютуз и с помощью дальномера вынесены из void loop? Их можно не выносить?
я их оформил как отдельные функции
если оставить в loop то придется один и тот же код вставлять несколько раз
Подскажите, пожалуйста, в чем может быть проблема. У меня скетч почти такой же, просто написан под другое приложение и исправлен под 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);
}
В проге Bluetooth RC Car есть иконки:Свет, стоп сигнал и аварийка, объясните про подключение светодиодов поподробней,пжалста.
а можете сделать точно такую машинку но с двумя моторами,сколько не пытался алгоритм ваш переделать не получается,просто у меня два мотора или может скетч есть,очень нужно
Другой шильд под моторы?на 2 выхода?или этот переделать на 2?
уже сделать ничего не могу - давно ее разобрал так как наигрался
скажи как переключение подключить,тут написано 28 и 29 это переключение,так вот с одной стороны подключить к кнопке а второе к чему что бы режимы переключить не пойму ни как а так всё вроде работает но перерывами потому что не знаю как переключить на блютуз и обратно подскажи,куда делся ты???
Всем привет! Друзья помогите, я как бы новичок и хочу построить робот на базе ардуино. Такой вопрос: а в какую программу загружать скетч?(как называется прога). На телефон я установил прогу Bluetooth RC controler.
https://www.arduino.cc/en/Main/Software
Делайте все в соответствии с постом, и у вас все получиться.я все заказал на алиэкспресе (там дешевле), и взял за основу ардуино уно, т.к. если на меге собирать остается очень много свободных портов, но если новичок, сразу попробуйте что нибудь попроще. В проге что вы скачале смотрите на какой пин задействованы свет, стоп сигналы, аварийка, и гудок и просто их добавляете в скетч. удачи!!!
P/S/ я наигрался на 2-й день
Ставь модуль для работы с SD картами. Составляй планы помещения. Вытащи с мышек оптический датчик и сделай распознавание лиц. Сделай в машинке режим следования за хозяином и исследования окружающего пространства. Там много чего накрутить можно. Поставь в него GPS датчик и пусть шурует в заранее заданную точку пространства.
Собери две машинки и пусть воюют между собой с помощью ИК-передатчиков и приемников. Задач дочерта. Уже месяца три балуюсь.
как переключить режыми к чему подключавть 28 и 29 к кнопке а втроой провод где минус или что?????????????
Все собралось, все работает. Но хочу небольшое замечание сделать.
Зачем было городить кнопки, когда в программе есть возможность включения фар? Включил фары - идет по дальномеру. Отключил - идет по управлению оператора.
Еще показалась интересной мысль распределения задач на две ардуино уно. Одна чисто под управление движками, вторая с внешней периферией работает. Трех пинов вполне должно хватить для обмены между платами. Выигрыш - в оперативности обработки сигналов за счет параллельной обработки. Если выпускать машинку на улицу, то скорость реакции будет иметь значение. ;)
дайте кто скетч залить для ардуино мега 2560 для двух моторов,поставил драйвер моторов на два колеса и серво привод и дальномер,что бы не сталкивался но тут какие то диоды,кнопки,зачем это мне,мне нужно что бы или сам ехал или через блютуз или вайфай работал на сотовом,потом хочу эту технологию на снегоуборщика поставить самодельного,но пока мелкий не протестирую,ставеть не буду дак вот скетч нужен
Кнопки тебе не очень нужны. Просто в блоке "Выбор режима работы" перед свичем принудительно присвой переменной 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;
}
А по двум движкам - не ленимся, батенька, ручками блокируем код, относящийся к отсутствующим двигателя. Хотя, если у тебя мотор-шилд такой же, то можно ничего не менять.
А как проблему с питанием и гидроизоляцией решал?
значит всё тоже самое залить и просто равно 3 поставить,так?просто я скетч залил,дак он что минуту чего то ждёт а потом серво в лево и в право и дальномер пробивает зону,ну что бы не столкнуться потом пару раз проедет и всё,я думаю из за этих кнопок,ну я попробую залить и так сделать,а что про питание писали,вы про снегоуборщик,если про него,так есть китайский регулятор напруги,но он мне даже не нужен потому что я решил использовать контроллеры от электро велосипеда но минус один,моторы крутит прямо,а назад не поедет,в силу недостатка денег всё движется пока медленно и мой робот снегоуборщик на шести колёсах пока кроме рамы и моторов и контроллеров не ставил ещё,правда было маленькое испытание,едет но пока с трудом на всё нужны деньги и время,чего мне больше всего не хватает сейчас
как эти кнопки подключить 28 и 29,если не нужны то через что тогда подключать через блютуз получиться?
а ещё хотел спросить а как ещё добавить,что бы ехал к примеру до забора потом разворачивался и рядом где ехал только на пол метра дальше обратно ехал,потом опять на два метра от угла и так туда сюда но отдалялся и чистил снег,может камеру поставить или где раздобыть прогу робота пулисоса но что бы карту делал местности и потом ездил да убирал,была бы такая система я бы давно поставил а пока давольствуюсь тем что есть,да и проще всего
я одно не понял,если в свиче поставить 3 то как переключатся на то,что бы с сотового можно было переключить на автономного,то есть что бы сам ездил и обратно на ручное управление,если поставлю Кнопки тебе не очень нужны. Просто в блоке "Выбор режима работы" перед свичем принудительно присвой переменной vmode=3. Должно получиться так.
/* Выбор режима работы */
vmode=3;
то где кнопка через блютуз будет на переключение на блютуз и обратно на автомат так скажем мне нужно что бы два в одном было и сам ездил и через блютуз переключил и он поехал,видосов много смотрел но то ездит сам или по блютуз но отдельно,мне всё вместе нужно на ардуино мега 2560 и через этот мотор шилд
Парни мне одному так кажеться или он местами
8 - GND - к GND Arduino Mega 2560
9 - +5 V - к +5 V Arduino Mega 2560
попутал?
хм
Саша тоже так думаешь?
да вроде проблем у меня нету,как только переключить режимы,у меня есть другие скетчи но там всё отдельно,если едет автономно то не переключишь через блютуз,а есть и с блютуз но не автономно но там за то можно свет включить передних фар и задних и аварийку,но мне нужно что бы ещё переключить можно на другой режим,а здесь ты разобрался с кнопками 28 и 29,как переключить???куда проводки тыркнуть что бы режим переключился,а то без диодов и кнопок потрогаешь он пол минуты сам поездит и станет,а как переключить на блютуз тыркал в разные разьёмы так и не переключился на блютуз бывает через блютуз дёрнеться,и резко в автономный режим переключаеться
я же тебе говорю скорее всего разъемы перепутаны.
да какая разница я другой скетч выложил по блютуз правда но пока и так сойдёт
#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);
}