Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр Квадрокоптеры

Гоночная машинка на bluetooth управлении.

Привет всем. Сегодня я постараюсь представить вам обзор детского автомобиля, управляемого по bluetooth через телефон или планшет.

Так как продавец сделал мне скидку после того, как я отправила ему ссылку на обзор конструктора, я поставила п.18. Честно говоря, посылка шла очень долго, и я подумала, что она либо потерялась, либо я привыкла, что в последнее время с почтой все идет гладко. Несмотря на время доставки, коробка не помялась, так что можно дарить в подарок. Китайская упаковка для игрушек также служит витриной. Изображение всех возможных вариантов представлено на каждой стороне коробки. Кроме того, можно загрузить QR-код, связанный с приложением для Android и iOS.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Что же предлагает производитель?

● Масштаб 1:20
● Два ведущих колеса
● Управление через блютуз
● Голосовое управление
● Программируемое движение

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

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

В первую очередь, давайте посмотрим на саму машину. Она выглядит интересно для ребенка, благодаря своим ярким цветам и гоночному виду. Пластик – это корпус машины, и он не водонепроницаем, поэтому это машина для сухой погоды или для квартиры.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

В нижней части машины находится отсек для аккумулятора, батарея емкостью 700 мАч 4,8 вольт, состоящая из четырех элементов AA NiCd. Есть также индикатор поворота, если машина едет не прямо, и кнопка для включения игрушки.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

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

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Отделка автомобиля держится на 3 штифтах. Если есть возможность, ее можно легко снять и заменить. Фактический корпус находится ниже, где расположена управляющая электроника.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

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

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

На фотографии виден чип управления двигателем – микросхема bluetooth с выцветшей маркировкой. В корпусе заднего моста установлен коллекторный двигатель и коробка передач. На шестернях имеется смазка.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Как только я загрузил QR-код, я начал тестировать машину. Что представляет собой приложение? Похоже, что оно написано в стенде, но оно работает, хоть и не часто, но бывают сбои. С помощью приложения можно управлять им с помощью кнопок на экране, а также голосовыми командами, но это для особых извращенцев). Команды очень простые, такие как бежать, влево и стоп. Копейки, которые я использовал для выполнения команд, доказали, что произношение у меня среднее. Кроме того, есть конструктор маршрутов, который позволяет добавлять фрагменты маршрута, например, 2 секунды прямо направо, и пусть машина следует по этому пути. Голосовое управление не произвело на меня такого впечатления, как это. Вот несколько скриншотов приложения.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Все значки управления находятся в верхней части главного экрана приложения. Похоже, что индикатор заряда батареи слева – это просто дизайн, так как он показывал 100%, когда не было движения. Объяснение кнопок и голосового управления представлено в меню настроек. Дополнительно есть кнопки для включения голосового управления, смены управления, выбора песни, под которую катится машина, включения построителя маршрутов и выбора фона рабочего стола. Чтобы подключиться к машине, нажмите на крайнюю правую кнопку.

На самом деле, если вычесть 5 фунтов, это отличная игрушка для ребенка, если учесть, что я купил ее, когда она стоила 16 долларов. Автомобиль катится по ковру так же хорошо, как и по асфальту, особенно если асфальт скользкий. Пороги на квартире в порядке. Это не слишком сложно, и вы можете управлять им без телефона). Аккумулятора хватает ровно на 20 минут работы. Машину планировали сразу отдать маленькому племяннику, но сын сначала сам решил, что это нормально). Пожалуйста, поймите, что это просто интересная игрушка для ребенка, а не гоночный автомобиль для заядлых RC-споттеров. Я думаю, что это так, и вы можете увидеть на видео, как он ездит. Если бы снова были скидки, вы могли бы в принципе взять их своему ребенку. Спасибо всем вам за то, что читаете.

Во время написания данного обзора я получила бесплатный продукт от магазина. Согласно Правилам сайта, отзыв опубликован в соответствии с пунктом 18.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой

Работа с микроконтроллерами, на мой взгляд, увлекательна тем, что вы можете создавать собственное радиоуправляемое оборудование. Доступно множество вариантов дистанционного управления. Используя микроконтроллер esp32, мы проиллюстрируем, как настроить такое управление.

В свое время я, как и многие, пошел по пути создания различных устройств на базе модулей HC-05, HC-06:

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр
Источник картинки: www.microsin.net

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

Такая комбинация была бы осуществима в начале 2022 года, но сейчас требуется более современный подход. В частности, мы будем использовать esp32 в качестве микроконтроллера, которым мы будем управлять с экрана нашего смартфона.

Существуют различные способы отправки команд управления, но для данного проекта, поскольку мы рассматриваем создание устройства реального времени, имеет смысл использовать протокол websockets.

В двух словах, все сводится к нажатию кнопки управления и движению автомобиля, отпусканию кнопки и остановке автомобиля (хотя могут быть и другие вещи, например, ответы машины, отправленные нам).

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

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

Что касается подключения, то микроконтроллер будет подключен через wifi, а точкой доступа будет смартфон. панель управления та же самая, и мы будем управлять машиной соответственно). Таким образом, сначала мы должны настроить и запустить точку доступа на смартфоне, прежде чем вводить ее параметры доступа в наш скетч:

// вставляем ниже SSID и пароль для своей WiFi-сети:
const char* ssid     = "сюда название сети";
const char* password = "сюда пароль";

Как только веб-сервер будет запущен на порту 80, мы создадим объект socket, который будет работать с веб-сокетами:

AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

Далее мы должны создать веб-страницу, которую увидит пользователь. Эта страница должна быть помещена в массив index_html.

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

Щелчки обрабатываются с помощью кода JavaScript, в котором настраиваются сокеты и задаются реакции на события:

  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  window.addEventListener('load', onLoad);
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; 
  }
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }

Кроме того, инициализируются обработчики для нажатия кнопок:

  function onLoad(event) {
    initWebSocket();
    initButton();
    initButton2();
    initButton3();
    initButton4();
  }

И указывает конкретный сценарий, который должен произойти в начале и в конце прикосновения (будет вызвана соответствующая функция):

  function initButton() {
      document.getElementById('button').addEventListener('touchstart', forward, false);
      document.getElementById('button').addEventListener('touchend', stopper, false);
  }

   function initButton2() {
      document.getElementById('button2').addEventListener('touchstart', left, false);
      document.getElementById('button2').addEventListener('touchend', stopper, false);

 function initButton3() {
      document.getElementById('button3').addEventListener('touchstart', right, false);
      document.getElementById('button3').addEventListener('touchend', stopper, false);
  }

   function initButton4() {
        document.getElementById('button4').addEventListener('touchstart', reverse, false);
        document.getElementById('button4').addEventListener('touchend', stopper, false);
    }

Когда происходит событие, эта функция соответствующим образом отправляет определенное сообщение:

  function forward(){
    websocket.send('forward');
  }

  function left(){
    websocket.send('left');
  }

  function right(){
    websocket.send('right');
  } 

    function reverse(){
      websocket.send('reverse');
    }

 function stopper(){
    websocket.send('stop');
  }

Теперь нам нужно создать обработчик сообщений, который будет вызываться каждый раз при получении нового сообщения. Как вы можете видеть, при каждом событии происходит вывод служебного сообщения на Serial и регистр переменной строки состояния. Необходимо написать логику предстоящих событий. Например: “если мы едем вперед и получаем сообщение повернуть налево, то машина начинает медленно поворачивать налево”.

Вам нужно понять, что происходит в данный момент, посмотрев на состояние переменной state:

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

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

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %sn", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnectedn", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

Существует специальная функция, которая используется для инициализации веб-сокета:

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

Затем настройте сервер на прослушивание входящих GET сообщений и запустите его:

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Start server
  server.begin();

В соответствии с тем, что мы говорили ранее, в нашей системе смартфон функционирует как точка доступа, а esp32 – как клиент. Посмотрите, что происходит, когда запущен монитор COM-порта и точка доступа настроена на смартфоне. Это показывает, что esp32 успешно подключился к смартфону, получил IP-адрес и вывел отчет на COM-порт:

Смотрите про коптеры:  Обзор DJI Mavic Pro. Лучший квадрокоптер. Опыт 3 месяцев эксплуатации - MegaObzor

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Если мы попытаемся получить доступ к этому адресу с мобильного устройства, мы увидим сообщение от системы о том, что подключен клиент websocket. Когда мы нажимаем на кнопку, появляется соответствующее сообщение, а когда мы отпускаем кнопку, появляется сообщение “Стоп”. При выключении точки доступа появляется сообщение об отключении клиента:

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

После загрузки пульта дистанционного управления он будет выглядеть следующим образом:

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Это было сделано специально, чтобы облегчить управление, когда вы держите смартфон горизонтально.

Кроме того, wi-fi ограничит дальность управления при использовании этого метода. Вам придется изменить схему подключения, если вы планируете управлять устройством на расстоянии.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Для этого:.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Для этого необходимы N RF-модулей. Использование их с esp32 представляет свои трудности, особенно когда вам нужно адаптировать библиотеку RF24 так, чтобы программа использовала программную реализацию SPI вместо аппаратной. Это хорошо объяснено здесь.

Это все, что нужно! Код Websocket протестирован и работает. Ваша единственная задача – прописать свою реализацию, основанную на правильном типе движка/уровня.

Кодекс можно загрузить здесь.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Исходный код программы

В первом сегменте программы необходимо подключить выходные контакты к двигателям (через драйвер двигателя).

После установки направления действия этих контактов в функции настройки (для вывода данных) перезапустите устройство.

Далее мы будем считывать данные с последовательного порта Arduino, которые посылает модуль Bluetooth, и выполнять на нем соответствующие инструкции.

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

Полный текст программы ниже.

Подключаем bluetooth к машинке

Мы собираемся использовать модуль Bluetooth через SoftwareSerial (библиотеку SoftwareSerial.h), поэтому подключаем модуль блютуз к 3 и 4 цифровым пинам ардуино. RX к D3, TX к D4

Схема ардуино робота машинки 5
Схема подключения Bluetooth к ардуино машинке

Платформа для робота готова! Осталось только загрузить прошивку для Arduino и приложение для смартфона RC CAR. Обзор Android-приложений для Arduino можно найти на нашем сайте.

Роботизированная машина. часть iii: bluetooth

С точки зрения программирования и управления Bluetooth эта статья интересна. Ранее мы подробно обсуждали вопросы сборки.

Первым шагом является оснащение робота модулем HC-06 для связи по Bluetooth. Необходимо заранее сконфигурировать HC-06. Можно использовать HC-05, но он дороже, и его функциональность будет избыточной для этой задачи.

Далее необходимо установить на телефон бесплатную программу Bluetooth RC Controller. Имитируя основные кнопки пульта дистанционного управления, программа передает команды по Bluetooth в текстовом формате.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Интерфейс программы прост в использовании, как вы можете видеть. В верхнем левом углу вы можете видеть индикатор подключения HCM-06 (зеленый цвет означает успешное подключение). Там же находится компас, который показывает выбранное направление движения, а также элементы управления по периметру. Наша машина должна была быть построена с использованием всего. Перечисляем слева направо.

Таким образом, почти все кнопки на пульте дистанционного управления управляли машиной напрямую. Хотя код управления скоростью пришлось писать отдельно и отлаживать. Еще одну интересную вещь мы сделали с диагональными направлениями. Изменяя скорость на левой и правой стороне, реализовали их.

Прошивка показана ниже. В моей версии опрос сонара отключен, но его можно восстановить. При ручном управлении я обнаружил, что невозможно остановиться возле препятствия.

*

// 4WD RoboCar
// Sonar   Bluetooth
// 2022-January-20
// v.11a (bluetooth)
// (c) 2022, Vladimir E. DRACH

// Global variables:
int  Critical = 14;     // Критическое расстояние до препятствия в [см]
int  BT_Step  = 10;     // Время движения при получении одного СИМВОЛА по BT [мс]
byte randomNumber;      // Случайное число
byte Cost = 60;         // Штраф (назначается за неспособность ехать вперёд)
byte Profit = 180;      // Очки, т.е. "прибыль", которая плавно растёт при движении вперёд
byte velocity = 220;    // Скорость моторов [1..255]
                            // Подобрать экспериментально:
const byte SPEED_MIN = 100; // минимальная скорость моторов, если меньше - моторы не смогут вращаться
const byte SPEED_MAX = 250; // максимальная скорость моторов

// для управления по Bluetooth
char btCommand = 'S';
// счетчики для определения потери связи с Bluetooth
unsigned long btTimer0 = 2000;  //Stores the time (in millis since execution started)
unsigned long btTimer1 = 0;     //Stores the time when the last command was received from the phone

// Описываем подключение драйвера двигателей
// A - правый борт
// В -  левый борт

int enableB = 3; //~ 
int pinB2   = 4; // 
int pinB1   = 5; // 
int enableA = 6; //~ 
int pinA1   = 7; //~ 
int pinA2   = 8; //

#define illumination A0 // подключаем составной светодиод

// Подключаем ультразвуковой датчик
#define trigPin 9
#define echoPin 10

#define light 11 // На этот вывод подключены фары

int Buzzer = 12;// Подключаем зуммер 12 (!)

// Фоторезистор подключен к АЦП
#define PHOTO_SENSOR A5

#define Sweep 8000 // скорость нарастания и убывания частоты
#define Woo_wait_sec 2 // сколько с. длится гудение на макс. частоте

void setup() {
  // Определяем направление работы линий
   pinMode (enableA, OUTPUT);
   pinMode (pinA1,   OUTPUT);
   pinMode (pinA2,   OUTPUT);
   pinMode (enableB, OUTPUT);
   pinMode (pinB1,   OUTPUT);
   pinMode (pinB2,   OUTPUT); 
   pinMode (13 ,     OUTPUT);
   pinMode (light ,  OUTPUT);
   pinMode (trigPin, OUTPUT);
   pinMode (echoPin, INPUT) ;
   pinMode (illumination, OUTPUT);
 enableMotors();
 SayBeep();
 delay(2000);
 bii();
 digitalWrite(13,  LOW);    // Выключаем встроенный диод
 Serial.begin(9600);        // Инициализация последовательного порта
}

// Описываем варианты работы моторов
void motorAforward() {
 digitalWrite (pinA1, HIGH);
 digitalWrite (pinA2, LOW);
}
void motorBforward() {
 digitalWrite (pinB1, LOW);
 digitalWrite (pinB2, HIGH);
}
void motorAbackward() {
 digitalWrite (pinA1, LOW);
 digitalWrite (pinA2, HIGH);
}
void motorBbackward() {
 digitalWrite (pinB1, HIGH);
 digitalWrite (pinB2, LOW);
}
void motorAstop() {
 digitalWrite (pinA1, HIGH);
 digitalWrite (pinA2, HIGH);
}
void motorBstop() {
 digitalWrite (pinB1, HIGH);
 digitalWrite (pinB2, HIGH);
}
void motorAon() {
 digitalWrite (enableA, HIGH);
}
void motorBon() {
 digitalWrite (enableB, HIGH);
}
void motorAoff() {
 digitalWrite (enableA, LOW);
}
void motorBoff() {
 digitalWrite (enableB, LOW);
}

// Описываем варианты движения машины
void goForward (int duration) {
 motorAforward();
 motorBforward();
 delay (duration);
}
void goBackward (int duration) {
 motorAbackward();
 motorBbackward();
 delay (duration);
}
void rotateRight (int duration) {
 motorAbackward();
 motorBforward();
 delay (duration);
}
void rotateLeft (int duration) {
 motorAforward();
 motorBbackward();
 delay (duration);
}
void FullStop (int duration) {
 motorAstop();
 motorBstop();
 delay (duration);
}
void disableMotors() {
 motorAoff();
 motorBoff();
}
void enableMotors() {
 motorAon();
 motorBon(); 
 // SetVelocity(SPEED_MAX, SPEED_MAX); не очень работает :(
}

void SetVelocity(int A, int B)
{         analogWrite (enableA, A);
          analogWrite (enableB, B); }

void CheckLight () {
  int val = analogRead(PHOTO_SENSOR);
  if (val < 500) {
    // Темновато, включаем фары
    digitalWrite(light, HIGH);
   } else {
    // Светло, выключаем фары
    digitalWrite(light,  LOW);
   }
}

// Пользуемся УЗ датчиком расстояния
int distance() {
  int duration, distance;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(1000);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1; // Переводим в сантиметры
  return distance;
}

// Функция запуска автомобиля
void launch() {
     int distance_measured;
     distance_measured = distance();
      // Serial.print(distance_0);
      // Serial.println(" сантиметров. ");
     SetVelocity (velocity, velocity);
      // Движемся вперёд, пока расстояние до преграды > критического [cm]
     while (distance_measured > Critical)
     {
     CheckLight ();  // проверяем, не пора ли зажигать фары?
     goForward(30); // Едем вперёд некоторое время
     randomNumber = random(1,100); // передёрнули затвор генератора ПСЧ
     if (Profit < 254 ) { Profit  ; };
     // Serial.print(Profit);
     // Serial.println(" очков. ");
     distance_measured = distance();
     }
     FullStop(100); // Останов, т.к. впереди помеха
}

void Woo(int freq, long duration){ // первый параметр частота, чем ниже он тем выше частота, второй длительность
  long time = duration/2/freq;
  for(long t = 0; t < time; t  )
  { digitalWrite(Buzzer, HIGH);
    delayMicroseconds(freq);
    digitalWrite(Buzzer, LOW);
    delayMicroseconds(freq); }
}

void Syren() {
    for(int i = 0; i <= 1; i  ){         // делаем виу-виу 2 раза
    for(int f = 2000; f >= 100; f=f-40){ // нарастание частоты
    Woo(f, Sweep); }
    // Woo(400, Woo_wait_sec*100);    // сколько длится гудение на максимальной частоте
    for(int f = 100; f <= 2000; f=f 40){ // убывание частоты
    Woo(f, Sweep); }
    }
    }

void panic() {
 int distance_tmp;
 int distance_new = 32000;
 int angle = 600;  // угол поворота, измеряем в [мс]
    FullStop(100); // Сначала останавливаемся
    Profit = 255;  // Забываем про старые штрафы!
    // Serial.print(Profit);
    // Serial.println(" очков. ");
    digitalWrite(illumination, HIGH); // включаем мигалку
    Syren ();
    Syren ();
    Syren ();
    delay(1000);  // пауза, для отдыха
    // Выполняем манёвры на высокой скорости (ведь паника!)
    analogWrite (enableA, velocity);
    analogWrite (enableB, velocity);
    // 0) Начинаем крутиться волчком в какую-то сторону:
    randomNumber = random(1,100);
    if (randomNumber < 50) { motorAbackward(); motorBforward(); }
                      else { motorBbackward(); motorAforward(); };
    // Истерично продолжаем крутиться, пока гудит сирена:
    Syren ();
    delay (1000); // Ждём 
    FullStop(1000);
    delay (100); // Ждём 
    // 1) Ищем хоть какое-то направление, куда вообще можно ехать
    distance_tmp = distance();
    do {
     rotateRight(angle); // Крутимся
     FullStop(1000); // Ждём и смотрим вдаль
     distance_tmp = distance();
     } while(distance_tmp < Critical); // повторяем поворот, если расстояние всё ещё мало

     SayBeep();
     // rotateLeft(angle); // Возвращаемся на один шаг
 
    // 2) Пытаемся выбрать лучшее направление!
     
    do {
    distance_tmp = distance();
    rotateRight(angle); // Крутимся и проверяем дистанцию
    FullStop(900); // Ждём и смотрим вдаль
    distance_new = distance();
    delay (800); // Ждём и смотрим вдаль
    } while( distance_new > distance_tmp );
                                   // Не угадали, раньше было лучше,
    rotateLeft(angle);             // поэтому поворачиваемся обратно
    FullStop(1000); // Восстанавливаем дыхание, успокаиваемся
    digitalWrite(illumination, LOW); // успокоились, выключаем мигалку
    delay (410); // Ждём
    SayBeep();
    }

void rollBack()
    {
    digitalWrite(13,  HIGH); // Включаем встроенный диод!
    // Сначала откатываемся назад на случайное количество шагов
    randomNumber = random(700,2100);
    //analogWrite (enableA, 150);
    //analogWrite (enableB, 189);
    goBackward(randomNumber);
    FullStop(200); // Восстанавливаем дыхание, успокаиваемся
        
    // Случайным образом выбираем направление поворота:
    randomNumber = random(1,100);
       
     do { // поворачиваемся в выбранную сторону на случайный угол
     if (randomNumber < 50) { rotateRight(random(450,1300)); } else { rotateLeft(random(350,1400)); };
     FullStop(1000); // Выключаем моторы
     tone(Buzzer, 600, 333);
     delay (700); // передышка!
     } while( distance() < Critical ); // повторяем поворот, если расстояние всё ещё мало

    analogWrite (enableA, velocity);
    analogWrite (enableB, velocity);
    FullStop(600); // Восстанавливаем дыхание, успокаиваемся
    digitalWrite(13,  LOW); // Выключаем встроенный диод
    // SayBeep();
    delay (200); // передышка!
    } 

void avoid() {
    CheckLight ();  // проверяем, не пора ли зажигать фары?
    tone(Buzzer, 2100, 110);
    delay (700); // передышка!
    // Штрафуем сами себя:
    if (Profit > Cost) {
    Profit = Profit - Cost; // Ещё есть возможность оплатить штраф,
    rollBack();             // тогда откат назад с разворотом
     // Serial.print(Profit);
     // Serial.println(" очков. ");
    } else {
    // Нельзя штрафовать, всё плохо, значит запутались - паникуем
    panic();
    }
}

void SayBeep(){
    tone(Buzzer, 700, 109);
    delay(200);
    tone(Buzzer, 1200, 109);
    delay(200);
    tone(Buzzer, 2600, 240);
    delay(350);
    noTone(Buzzer);
}

void boo(){
      tone(Buzzer, 600, 200);
      delay (300);
      tone(Buzzer, 410, 600);
      delay (600);
}

void bii(){
      tone(Buzzer, 1611, 90);
      delay (150);
      tone(Buzzer, 1611, 90);
      delay (150);
      tone(Buzzer, 2111, 400);
      delay (440);
}

void SafeForward (int duration){
  int distance_measured;
  distance_measured = distance();
  if ( distance_measured > Critical )
      {goForward(duration);}
      else {
      FullStop(10);
      boo(); }
}

void BluetoothControl() {
     for(int i = 0; i <= 4; i  ){
     // digitalWrite(illumination, HIGH); // включаем мигалку
     digitalWrite(13,  HIGH); // Включаем встроенный диод!
     FullStop(80);
     // digitalWrite(illumination, LOW); // вЫключаем мигалку
     digitalWrite(13,  LOW); // Включаем встроенный диод!
     FullStop(900);
     velocity = SPEED_MIN   10;         // Выставлям скорость поменьше, т.к.
     SetVelocity(velocity, velocity);   // на Android будет миниальная скорость по умолчанию!
     }
     do{
     // CheckLight ();  // проверяем, не пора ли зажигать фары?
     aquire();
     }
     while ( 1==1 );
}

void SelfControl() {
     do{
     randomNumber = random(2,5); // вхолостую выбираем псевдо-случайное число
     launch(); // запускаем автомобиль вперёд до встречи с преградой
     avoid();  // откатываемся от препятствия и как-то поворачиваемся
     CheckLight (); // проверяем, не пора ли зажигать фары?
     }
     while ( 1==1 );
}

void aquire ()
{
  if (Serial.available() > 0) {
    btTimer1 = millis();
    btCommand = Serial.read();
    switch (btCommand){
    case 'F':
      goForward(BT_Step); // Можно просто ехать вперёд наобум,
      // SafeForward (BT_Step); // а можно включить сонар
      break;
    case 'B':
      goBackward(BT_Step);
      break;
    case 'L':
      rotateLeft(BT_Step);
      break;
    case 'R':
      rotateRight(BT_Step);
      break;
    case 'S':
      FullStop(BT_Step);
      break;
    case 'G':  // Вперёд, подкручивая вправо
      if (velocity < SPEED_MAX-99) {
      SetVelocity((velocity 99), (velocity-99));}
      else {SetVelocity(SPEED_MAX, SPEED_MIN);} // выставили дифференциал
      goForward (BT_Step);
      SetVelocity(velocity, velocity); // вернули скорость
      break;
    case 'I':  // Вперёд, подкручивая влево
      if (velocity < SPEED_MAX-99) {
      SetVelocity((velocity-99), (velocity 99));}
      else {SetVelocity(SPEED_MIN,SPEED_MAX);} // выставили дифференциал
      goForward (BT_Step);
      SetVelocity(velocity, velocity); // вернули скорость
      break;
    /*case 'J':  //BR
      if (velocity < SPEED_MAX-80) {
      SetVelocity((velocity-80), (velocity 80));}
      else {SetVelocity((velocity-80),SPEED_MAX);} // выставили дифференциал
      goBackward(BT_Step);
      SetVelocity(velocity, velocity); // вернули скорость
      break;
    case 'H':  //BL
      if (velocity < SPEED_MAX-80) {
      SetVelocity((velocity 80), (velocity-80));}
      else {SetVelocity(SPEED_MAX, (velocity-80));} // выставили дифференциал
      goBackward(BT_Step);
      SetVelocity(velocity, velocity); // вернули скорость
      break;
      */
    case 'W':  //  Зажгли фары
      digitalWrite(light, HIGH);
      break;
   case 'w':  // Погасили фары
      digitalWrite(light, LOW);
      break;
   case 'D':  // Everything OFF
      FullStop(100);
      break;
   case 'X': // аварийка
      digitalWrite(illumination, HIGH);
      break;
   case 'x': // аварийка
      digitalWrite(illumination, LOW);
      break;      
   case 'U':  // Back ON
      digitalWrite(13,  HIGH);  // Включаем встроенный диод
      break;
   case 'u':  // Back OFF
      digitalWrite(13,  LOW);    // Выключаем встроенный диод
      break;
   case 'V': // Пискнуть весело (в оригинале - гудок ВКЛ)
      bii();
      break;
   case 'v': // Пискнуть грустно (в оригинале (гудок ВЫКЛ)
      boo();
      break; 
   default:  // Get SPEED_CURRENT
      if ( btCommand == 'q' ){
         velocity = SPEED_MAX;
         SetVelocity(velocity, velocity);
         } else {
        // Символы '0' - '9' эквивалентны кодам integer 48 - 57 соответственно
        if ( (btCommand >= 48) && (btCommand <= 57) ) {
          // Subtracting 48 changes the range from 48-57 to 0-9.
          // Multiplying by 25 changes the range from 0-9 to 0-225.
          velocity = SPEED_MIN   (btCommand - 48) * 15;
          SetVelocity(velocity, velocity);
        }
      } // else
    } // switch
  } // if (Serial.available() > 0)
  else {
    btTimer0 = millis();  // Узнаём текущее время (millis since execution started)
    //Check if it has been 500ms since we received last btCommand.
    if ((btTimer0 - btTimer1) > 800)   {
      //More than 800 ms have passed since last btCommand received, car is out of range.
      FullStop(1000);
      digitalWrite(illumination, HIGH); // включаем мигалку
      boo ();
      FullStop(4000);
      Syren();
      FullStop(8000);
    }
  }
}

void loop() {
     CheckLight ();  // проверяем, не пора ли зажигать фары?
     // Serial.println("System ready...");
     if ( distance() > Critical )
        {                     // Путь вперёд свободен,
          SelfControl();      // робот отправляется в самостоятельное путешествие
        } else {
          BluetoothControl(); // Впереди преграда, отдаём управление водителю
        }
     }

*

Выбор режима (ручной или демонстрационный) осуществляется в самом начале путем определения расстояния до препятствия. При включении машина стоит лицом к стене и управляется вручную через Bluetooth. При включении перед машиной нет препятствий – самостоятельное движение (демо-режим).

Смотрите про коптеры:  Профессиональный квадрокоптер купить в Москве, доставка по России и СНГ

§

Устройство было размещено внутри коробки из-под конфет. В нее встроены латунные стойки, на которых будет держаться модуль микроконтроллера Arduino UNO, управляющий трехцветным (сверхъярким) светодиодом. Кроме того, там был корпус для батареек АА, причем батарейки от радиоуправляемой машинки тоже отлично подошли – в общем, их можно переработать.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Меня осенила внезапная идея: а есть ли другой способ управлять лампой? Мое внимание привлек миниатюрный джойстик. Это именно то, что нам нужно!

Соответственно, светильник плавно меняет цвета с красного на зеленый и синий, но при нажатии на кнопку джойстика переходит в режим ручного управления (в котором интенсивность каждого цвета определяется положением ручки джойстика). При повторном нажатии кнопки происходит выход из ручного режима.

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Текст программы был основан на открытых источниках, но затем сильно изменен. Соответственно, ночное освещение становится более мягким и нежным.

const int pinRed    = 11;
const int pinGreen  =  9;
const int pinBlue   = 10;
const int swPin     = A5; 
const int pinX      = A4; // X 
const int pinY      = A3; // Y 
const int ledPin    = 13;
boolean ledOn  = false; // текущее состояние кнопки
boolean prevSw = false; // предыдущее состояние кнопки

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(pinRed, OUTPUT);
  pinMode(pinGreen, OUTPUT);
  pinMode(pinBlue, OUTPUT);
  pinMode(pinX, INPUT);
  pinMode(pinY, INPUT);
  pinMode(swPin, INPUT);  
  digitalWrite(swPin, HIGH); // включаем встроенный подтягивающий резистор
}

boolean isLedOn() { // ОПРЕДЕЛЯЕМ НАЖАТИЕ КНОПКИ
  if (digitalRead(swPin) == HIGH && prevSw == LOW) {
    ledOn = !ledOn;
    prevSw = HIGH;
  }
  else  prevSw = digitalRead(swPin); 
  digitalWrite(ledPin, ledOn); // включаем светодиод на пине 13
  return ledOn;
}

void CtlMode() { // РЕЖИМ "Ручное управление"
  int X = analogRead(pinX); // считываем положение джойстика
  int Y = analogRead(pinY);
  int BLUE  = map(Y, 000, 1023, 0, 255); // маппинг значений
  int GREEN = map(X, 512, 1023, 0, 255);
  int RED   = map(X, 511, 0, 0, 255);
  analogWrite(pinRed, RED);     // включение каналов R,G,B
  analogWrite(pinGreen, GREEN);
  analogWrite(pinBlue, BLUE);
}

void DemoMode() { // РЕЖИМ "Демонстрация"
    for (int i=0; i <= 255; i  ) {
      if (isLedOn()) { break; } // при нажатии кнопки выходим из цикла
      analogWrite(pinRed, i); // работает канал RED
      analogWrite(pinGreen, 0);
      analogWrite(pinBlue, 0);  
      delay(7);
    }
    for (int i=255; i >= 0; i--) {
      if (isLedOn()) { break; } // при нажатии кнопки выходим из цикла
      analogWrite(pinRed, i);   // работает канал RED
      analogWrite(pinGreen, 0);
      analogWrite(pinBlue, 0);  
      delay(7);
    }
    for (int i=0; i <= 255; i  ) {
      if (isLedOn()) { break; } // при нажатии кнопки выходим из цикла
      analogWrite(pinRed, 0);
      analogWrite(pinGreen, 0);
      analogWrite(pinBlue, i);  // работает канал BLUE
      delay(7);
    }
    for (int i=255; i >= 0; i--) {
      if (isLedOn()) { break; } // при нажатии кнопки выходим из цикла
      analogWrite(pinRed, 0);
      analogWrite(pinGreen, 0);
      analogWrite(pinBlue, i);  // работает канал BLUE
      delay(7);
    }
    for (int i=0; i <= 255; i  ) {
      if (isLedOn()) { break; } // при нажатии кнопки выходим из цикла
      analogWrite(pinRed, 0);
      analogWrite(pinGreen, i); // работает канал GREEN
      analogWrite(pinBlue, 0);  
      delay(7);
    }
    for (int i=255; i >= 0; i--) {
      if (isLedOn()) { break; } // при нажатии кнопки выходим из цикла
      analogWrite(pinRed, 0);
      analogWrite(pinGreen, i); // работает канал GREEN
      analogWrite(pinBlue, 0);  
      delay(7);
    }
}

void loop() { // если нажата кнопка и горит светодиод на пине 13, включаем режим "Ручое управление"
  if (isLedOn()) CtlMode(); 
  else DemoMode(); // иначе включаем демонстрационный режим
}


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

Смотрите про коптеры:  Будущее голосовых помощников: тенденции и прогнозы

§

Серво акселерометр

Акселерометр ADXL345 отлично подходит для измерения статического ускорения при свободном падении, когда требуется измерение наклона. Он также подходит для измерения динамического ускорения в результате движения или удара. Высокое разрешение (4 мг/ЛСБ) позволяет измерять изменение наклона менее одного градуса.

Ниже описаны этапы сборки устройства. Для передачи информации о положении в микроконтроллерный модуль ADXL345, который имеет диапазон -16g и 13-битное разрешение, используется I2C (или SPI). Микроконтроллеры декодируют данные акселерометра и используют функцию преобразования atan2 для их конвертации.

Это производит управляющее воздействие на серводвигатель. Для серводвигателей нет библиотек, что является важной особенностью.

Ниже приведен перечень тестов программы.

/*
  Подключение акселерометра по шине I2C:
  VCC: 5V
  GND: ground
  SCL: UNO SCL (А5?)
  SDA: UNO SDA (А4?)
*/

#include <Servo.h>
Servo motor; // Определяем имя серво-привода
#include <Math.h> // Вроде, нужна для atan2
#include <Wire.h>
// Registers for ADXL345
#define ADXL345_ADDRESS (0xA6 >> 1)  // address for device is 8 bit but shift to the
// right by 1 bit to make it 7 bit because the
// wire library only takes in 7 bit addresses
#define ADXL345_REGISTER_XLSB (0x32)

float Angle;      // угол поворота мотора
float prev_Angle; // временная переменная для угла
float value; // промежуточное значение Y

int accelerometer_data[3];
// void because this only tells the chip to send data to its output register
// writes data to the slave's buffer
void i2c_write(int address, byte reg, byte data) {
  // Send output register address
  Wire.beginTransmission(address);
  // Connect to device
  Wire.write(reg);
  // Send data
  Wire.write(data); //low byte
  Wire.endTransmission();
}

// void because using pointers
// microcontroller reads data from the sensor's input register
void i2c_read(int address, byte reg, int count, byte* data) {
  // Used to read the number of data received
  int i = 0;
  // Send input register address
  Wire.beginTransmission(address);
  // Connect to device
  Wire.write(reg);
  Wire.endTransmission();
  // Connect to device
  Wire.beginTransmission(address);
  // Request data from slave
  // Count stands for number of bytes to request
  Wire.requestFrom(address, count);
  while (Wire.available()) // slave may send less than requested
  {
    char c = Wire.read(); // receive a byte as character
    data[i] = c;
    i  ;
  }
  Wire.endTransmission();
}

void init_adxl345() {
  byte data = 0;
  i2c_write(ADXL345_ADDRESS, 0x31, 0x0B);   // 13-bit mode   - 16g
  i2c_write(ADXL345_ADDRESS, 0x2D, 0x08);   // Power register
  i2c_write(ADXL345_ADDRESS, 0x1E, 0x00);   // X
  i2c_write(ADXL345_ADDRESS, 0x1F, 0x00);   // Y
  i2c_write(ADXL345_ADDRESS, 0x20, 0x05);   // Z
  // Проверка работоспособности
  i2c_read(ADXL345_ADDRESS, 0X00, 1, &data);
  if (data == 0xE5)
    Serial.println("It works well!");
  else
    Serial.println("Failure... :(");
}

void read_adxl345() {
  byte bytes[6];
  memset(bytes, 0, 6);
  // Чтение шести байтов из ADXL345
  i2c_read(ADXL345_ADDRESS, ADXL345_REGISTER_XLSB, 6, bytes);
  // Распаковка данных
  for (int i = 0; i < 3;   i) {
    accelerometer_data[i] = (int)bytes[2 * i]   (((int)bytes[2 * i   1]) << 8);
  }
}

void setup() {
  motor.attach(9); // Прицепили серво-мотор (9 or 10)
  Wire.begin();
  Serial.begin(9600);
  for (int i = 0; i < 3;   i)   {
    accelerometer_data[i]  = 0;
  }
  init_adxl345();
}

void react() {
  // Теперь посылаем данные в мотор
  // Angle = map(value, 0, 1.0, 0, 180); // диапазон акселерометра отображается на 0..180 или 0..20 градусов
  Angle = value * 180.0;
  // Angle = constrain(Angle, 1, 180); // ограничиваем значения диапазоном от 1 до 180

  Serial.print("t");
  Serial.print("Угол: ");
  Serial.print(Angle);
  Serial.println("t");
  if (Angle != prev_Angle)
  {
    motor.write(Angle); // установить угол поворота мотора
    prev_Angle = Angle; // запомнить текущий угол
  }
}

void loop() {
  read_adxl345();
  Serial.print("ACCEL: ");
  Serial.print(float(accelerometer_data[0]) * 3.9 / 1000); // 3.9mg/LSB scale factor in 13-bit mode
  Serial.print("t");
  Serial.print(float(accelerometer_data[1]) * 3.9 / 1000);
  Serial.print("t");
  Serial.print(float(accelerometer_data[2]) * 3.9 / 1000);
  Serial.print("n");

  // value = float((accelerometer_data[1]) * 3.9 / 1000);

  value = atan2(float((accelerometer_data[1]) * 3.9 / 1000), float((accelerometer_data[0]) * 3.9 / 1000));
  if ( (value > 0) && (value < 1.0)) {
    react ();
   }
  delay(100);
}


§

Типовые характеристики дисплея следующие
Display Capacity: 16 × 2 characters.
Chip Operating Voltage: 4.5 ~ 5.5V.
Working Current: 2.0mA (5.0V).
Optimum working voltage of the module is 5.0V.
Character Size: 2.95 * 4.35 (W * H) mm.

Вот схема, показывающая, как подключаются модули Arduino Uno и Mega 2560.

 

 

Листинг программ для тестов можно использовать следующим образом

/* __________________
   1602 LCD 8-bit bus control
   __________________ */

int DI = 12;
int RW = 11;
int DB[] = {3, 4, 5, 6, 7, 8, 9, 10}; // use array to select pin for bus
int Enable = 2;

void LcdCommandWrite(int value) {
  // define all pins
  int i = 0;
  for (i = DB[0]; i <= DI; i  ) // assign value for bus
  {
    digitalWrite(i, value & 01); // for 1602 LCD, it uses D7-D0( not D0-D7) for signal identification; here, itΓÇÖs used for signal inversion.
    value >>= 1;
  }
  digitalWrite(Enable, LOW);
  delayMicroseconds(1);
  digitalWrite(Enable, HIGH);
  delayMicroseconds(1);  // wait for 1ms
  digitalWrite(Enable, LOW);
  delayMicroseconds(1);  // wait for 1ms
}

void LcdDataWrite(int value) {
  // initialize all pins
  int i = 0;
  digitalWrite(DI, HIGH);
  digitalWrite(RW, LOW);
  for (i = DB[0]; i <= DB[7]; i  ) {
    digitalWrite(i, value & 01);
    value >>= 1;
  }
  digitalWrite(Enable, LOW);
  delayMicroseconds(1);
  digitalWrite(Enable, HIGH);
  delayMicroseconds(1);
  digitalWrite(Enable, LOW);
  delayMicroseconds(1);  // wait for 1ms
}

void setup (void) {
  int i = 0;
  for (i = Enable; i <= DI; i  ) {
    pinMode(i, OUTPUT);
  }
  delay(100);
  // initialize LCD after a brief pause
  // for LCD control
  LcdCommandWrite(0x38);  // select as 8-bit interface, 2-line display, 5x7 character size
  delay(64);
  LcdCommandWrite(0x38);  // select as 8-bit interface, 2-line display, 5x7 character size
  delay(50);
  LcdCommandWrite(0x38);  // select as 8-bit interface, 2-line display, 5x7 character size
  delay(20);
  LcdCommandWrite(0x06);  // set input mode
  // auto-increment, no display of shifting
  delay(20);
  LcdCommandWrite(0x0E);  // display setup
  // turn on the monitor, cursor on, no flickering
  delay(20);
  LcdCommandWrite(0x01);  // clear the scree, cursor position returns to 0
  delay(100);
  LcdCommandWrite(0x80);  //  display setup
  //  turn on the monitor, cursor on, no flickering
  delay(20);
}

void loop (void) {
  LcdCommandWrite(0x01);  // clear the screen, cursor position returns to 0
  delay(10);
  LcdCommandWrite(0x80   3);
  delay(10);
  // Show welcome message
  LcdDataWrite('W');
  LcdDataWrite('e');
  LcdDataWrite('l');
  LcdDataWrite('c');
  LcdDataWrite('o');
  LcdDataWrite('m');
  LcdDataWrite('e');
  LcdDataWrite(' ');
  LcdDataWrite('t');
  LcdDataWrite('o');
  delay(10);
  LcdCommandWrite(0xc0   1); // set cursor position at second line, second position
  delay(10);
  LcdDataWrite('M');
  LcdDataWrite('G');
  LcdDataWrite('T');
  LcdDataWrite('U');
  LcdDataWrite('-');
  LcdDataWrite('w');
  LcdDataWrite('o');
  LcdDataWrite('r');
  LcdDataWrite('k');
  LcdDataWrite('s');
  LcdDataWrite('h');
  LcdDataWrite('o');
  LcdDataWrite('p');
  delay(3300);
  LcdCommandWrite(0x01);  // clear the screen, cursor returns to 0
  delay(10);
  LcdDataWrite('I');
  LcdDataWrite(' ');
  LcdDataWrite('a');
  LcdDataWrite('m');
  LcdDataWrite(' ');
  LcdDataWrite('a');
  LcdDataWrite(' ');
  LcdDataWrite('b');
  LcdDataWrite('o');
  LcdDataWrite('s');
  LcdDataWrite('s');
  delay(3000);
  LcdCommandWrite(0x02); // set mode as new characters replace old ones, where there is no new ones remain the same
  delay(10);
  LcdCommandWrite(0x80   5); // set cursor position at first line, sixth position
  delay(10);

  LcdDataWrite('V');
  LcdDataWrite('.');
  delay(220);
  LcdDataWrite('E');
  delay(220);
  LcdDataWrite('.');
  delay(220);
  LcdDataWrite(' ');
  LcdDataWrite('D');
  delay(220);
  LcdDataWrite('r');
  delay(220);
  LcdDataWrite('a');
  delay(220);
  LcdDataWrite('c');
  delay(220);
  LcdDataWrite('h');
  delay(5000);
}

После прошивки мы видим, что на дисплее появляется текст

 

В результате мы можем видеть пример жидкокристаллического дисплея

Делаем из смартфона websocket-пульт управления радиоуправляемой машинкой / Хабр

Основным недостатком этого решения является интенсивное использование линий ввода/вывода микроконтроллера или модуля микроконтроллера. Для уменьшения количества выводов рекомендуется использовать 4-битное шинное соединение.

Схема электропитания робота автомобиля

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

Далее выясним, как просто подать питание на моторы. Лучше припаять провода к моторам до начала сборки.

Схема ардуино робота машинки 2
Схема питания и подключения двигателей в ардуино автомобиле

Все довольно стандартно, и в Интернете можно найти десятки подобных примеров. У этой схемы есть один большой недостаток – когда батареи полностью разряжены, они перестают функционировать.

Машинка на Ардуино
Машинка на Ардуино

Схему необходимо изменить, чтобы включить контроллер разряда:

Схема ардуино робота машинки 3
Схема питания с контролем разряда аккумулятора

Теперь батареи защищены, но их невозможно перезарядить.

Питание ардуино
Питание робота Ардуино

Усилитель напряжения можно использовать для зарядки от 5 вольт до желаемого уровня заряда, который зависит от количества последовательно соединенных батарей. Устройство оснащено разъемом micro-USB, который может повредиться при частом использовании, поэтому мы рекомендуем установить запасной разъем для последующей зарядки с помощью 5-вольтового источника питания. Для зарядки двух литий-ионных батарей установите выходное напряжение 8,4 В.

Схема питания ардуино робота машинки
Схема питания с модулем зарядки для ардуино робота машинки
Оцените статью
Радиокоптер.ру
Добавить комментарий

Adblock
detector