Arduino. Проект «Робот-машина RoboCar4W» / Хабр

Arduino. Проект «Робот-машина RoboCar4W» / Хабр Роботы

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

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

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

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

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

С полным текстом программы можно ознакомиться ниже.

Код программы для «малыша»:

#include <SoftwareSerial.h>                                                      //  Подключаем библиотеку SoftwareSerial для общения с модулем по программной шине UART
#include <iarduino_Bluetooth_HC05.h>                                             //  Подключаем библиотеку iarduino_Bluetooth_HC05 для работы с Trema Bluetooth модулем HC-05
SoftwareSerial          softSerial(9, 10);                                       //  Создаём объект softSerial указывая выводы RX, TX (можно указывать любые выводы Arduino UNO). Вывод 2 Arduino подключается к выводу TX модуля, вывод 3 Arduino подключается к выводу RX модуля
iarduino_Bluetooth_HC05 hc05(13);                                                //  Создаём объект hc05 указывая любой вывод Arduino, который подключается к выводу K модуля
                                                                                 //  
uint8_t  pinShield_H2 = 4;                                                       //  Вывод, подключенный к драйверу, для задания направления вращения левым мотором
uint8_t  pinShield_E2 = 5;                                                       //  Вывод ШИМ, подключенный к драйверу, для задания скорости левого мотора
uint8_t  pinShield_E1 = 6;                                                       //  Вывод ШИМ, подключенный к драйверу, для задания скорости правого мотора
uint8_t  pinShield_H1 = 7;                                                       //  Вывод, подключенный к драйверу, для задания направления вращения правым мотором
uint8_t  pinLED_RED   = 12;                                                      //  Вывод с красным светодиодом
uint8_t  pinLED_BLUE  = 11;                                                      //  Вывод с синим светодиодом
uint16_t time_period  = 200;                                                     //  Частота мигания светодиодов (в миллисекундах)
uint8_t  valSpeed     = 255;                                                     //  Максимальная скорость ШИМ (число от 0 до 255)
bool     arrRoute[2]  = {1, 1};                                                  //  Направление движения для каждого мотора ([0]- правый мотор, [1] - левый мотор)
uint16_t arrSpeed[2];                                                            //  Скорость для каждого мотора ([0]- правый мотор, [1] - левый мотор)
uint32_t tmrLED;                                                                 //  Время  последнего включения светодиодов
uint32_t flgTime;                                                                //  Флаг для задания времени принятия пакетов от Bluetooth телефона
uint8_t  flg;                                                                    //  Флаг кнопок
uint32_t tmrWait;                                                                //  Время до начала сопряжения с новыми устройствами
bool     flg_LED;                                                                //  Флаг включения светодиодов
                                                                                 //  </iarduino_bluetooth_hc05.h></softwareserial.h>
void setup() {                                                                   //  
    // BLUETOOTH МОДУЛЬ                                                          //  
    Serial.begin  (9600);                                                        //  Инициируем передачу данных по аппаратной шине UART для вывода результата в монитор последовательного порта
    Serial.print  ("begin: ");                                                   //  Выводим текст "begin: " в монитор последовательного порта
    if (hc05.begin(softSerial))     {Serial.println("Ok");}                      //  Инициируем работу с Trema модулем hc05, указывая объект softSerial через который осуществляется связь по шине UART
    else                            {Serial.println("Error");}                   //  Если работа с модулем не инициирована, то выводим сообщение об ошибке
    tmrWait = millis();                                                          //  Устанавливаем таймер ожидания сопряжения
    while (!hc05.checkConnect() && millis()<tmrWait 60000) {;}                   //  Ждём в течении 60 секунд сопряжения с последним устройством из памяти
    if (millis()<tmrWait 60000)     {Serial.println("Connect with last ADR");}   //  Если сопряжение произошло, то выдаём в монитор порта сообщение об этом
    else {                                                                       //  Если сопряжение не произошло, то
    if (hc05.createSlave("BT_CAR", "1234"))                                      //  Создаем ведомую роль модулю, указывая его имя и pin-код (в примере имя = "BT_CAR", pin-код = "1234")
                                    {Serial.println("Slave create");}            //  Если ведомая роль была создана, выводим сообщение об успехе в монитор порта,
    else                            {Serial.println("Slave not create");}        //  а если не была создана - выводим сообщение об ошибке в монитор порта.
      }                                                                          //  
    // МОТОРЫ                                                                    //  
    pinMode(pinShield_H2, OUTPUT);                                               //  Конфигурируем вывод pinShield_H2 как выход (направление вращения левого мотора)
    pinMode(pinShield_E2, OUTPUT);                                               //  Конфигурируем вывод pinShield_E2 как выход (скорость вращения левого мотора, ШИМ)
    pinMode(pinShield_E1, OUTPUT);                                               //  Конфигурируем вывод pinShield_E1 как выход (скорость вращения правого мотора, ШИМ)
    pinMode(pinShield_H1, OUTPUT);                                               //  Конфигурируем вывод pinShield_H1 как выход (направление вращения правого мотора)
    // СВЕТОДИОДЫ                                                                //  
    pinMode(pinLED_RED,OUTPUT);                                                  //  Конфигурируем вывод pinLED_RED как выход 
    pinMode(pinLED_BLUE,OUTPUT);                                                 //  Конфигурируем вывод pinLED_BLUE как выход
    tmrLED = millis();                                                           //  Устанавливаем таймер светодиодов равным millis()
    flg_LED = 0;                                                                 //  Сбрасываем флаг светодиодов
}                                                                                //  
void loop() {                                                                    //  
  if (softSerial.available()) {                                                  //  Если есть принятые данные, то ...
    String str;                                                                  //  Создаём строку str
    while (softSerial.available()) {                                             //  Выполняем цикл пока есть что читать ...
      str  = char(softSerial.read());                                            //  Читаем очередной принятый символ из UART в строку str
      delay(5);                                                                  //  Задержка на 5 мс на случай медленного приёма
    }                                                                            //  Цикл завершён, значит читать больше нечего
                                            // КНОПКИ ДВИЖЕНИЯ                   //  
                               // Флаг времени            Флаг кнопки            //  
    if (str == "II") {    flgTime = millis();     flg = 1;    }                  //  Кнопка "стрелка вверх-влево"
    if (str == "FF") {    flgTime = millis();     flg = 2;    }                  //  Кнопка "стрелка вверх"
    if (str == "GG") {    flgTime = millis();     flg = 3;    }                  //  Кнопка "стрелка вверх-вправо"
    if (str == "RR") {    flgTime = millis();     flg = 4;    }                  //  Кнопка "стрелка влево"
    if (str == "SS") {    flgTime = millis();     flg = 5;    }                  //  СТОП
    if (str == "LL") {    flgTime = millis();     flg = 6;    }                  //  Кнопка "стрелка вправо"
    if (str == "JJ") {    flgTime = millis();     flg = 7;    }                  //  Кнопка "стрелка вниз-влево"
    if (str == "BB") {    flgTime = millis();     flg = 8;    }                  //  Кнопка "стрелка вниз"
    if (str == "HH") {    flgTime = millis();     flg = 9;    }                  //  Кнопка "стрелка вниз-вправо"
                                        // КНОПКИ ДОПОЛНИТЕЛЬНЫХ ФУНКЦИЙ         //  
                          // Если кнопка нажата        меняем флаг               //  
    if (str == "SWS" || str == "SwS") {flg_LED = !flg_LED;}                      //  Кнопка включения светодиодов
    if (str == "S0S") {flg     = 10;      }                                      //  Ползунок скорости в положении 0
    if (str == "S1S") {flg     = 11;      }                                      //  Ползунок скорости в положении 1
    if (str == "S2S") {flg     = 12;      }                                      //  Ползунок скорости в положении 2
    if (str == "S3S") {flg     = 13;      }                                      //  Ползунок скорости в положении 3
    if (str == "S4S") {flg     = 14;      }                                      //  Ползунок скорости в положении 4
    if (str == "S5S") {flg     = 15;      }                                      //  Ползунок скорости в положении 5
    if (str == "S6S") {flg     = 16;      }                                      //  Ползунок скорости в положении 6
    if (str == "S7S") {flg     = 17;      }                                      //  Ползунок скорости в положении 7
    if (str == "S8S") {flg     = 18;      }                                      //  Ползунок скорости в положении 8
    if (str == "S9S") {flg     = 19;      }                                      //  Ползунок скорости в положении 9
    if (str == "SqS") {flg     = 20;      }                                      //  Ползунок скорости в положении 10
    //  ======================================================================================================================================================
    switch (flg) {//Направление левого мотора    Направление правого мотора      Скорость левого мотора             Скорость правого мотора
      case 1:          arrRoute[1] = 1;             arrRoute[0] = 1;            arrSpeed[1] = (valSpeed / 2);       arrSpeed[0] = valSpeed;             break;       //  С-З
      case 2:          arrRoute[1] = 1;             arrRoute[0] = 1;            arrSpeed[1] = valSpeed;             arrSpeed[0] = valSpeed;             break;       //  С
      case 3:          arrRoute[1] = 1;             arrRoute[0] = 1;            arrSpeed[1] = valSpeed;             arrSpeed[0] = (valSpeed / 2);       break;       //  С-В
      case 4:          arrRoute[1] = 1;             arrRoute[0] = 1;            arrSpeed[1] = 0;                    arrSpeed[0] = valSpeed;             break;       //  З
      case 5:          arrRoute[1] = 1;             arrRoute[0] = 1;            arrSpeed[1] = 0;                    arrSpeed[0] = 0;                    break;       //  Стоп
      case 6:          arrRoute[1] = 1;             arrRoute[0] = 1;            arrSpeed[1] = valSpeed;             arrSpeed[0] = 0;                    break;       //  В
      case 7:          arrRoute[1] = 0;             arrRoute[0] = 0;            arrSpeed[1] = (valSpeed / 2);       arrSpeed[0] = valSpeed;             break;       //  Ю-З
      case 8:          arrRoute[1] = 0;             arrRoute[0] = 0;            arrSpeed[1] = valSpeed;             arrSpeed[0] = valSpeed;             break;       //  Ю
      case 9:          arrRoute[1] = 0;             arrRoute[0] = 0;            arrSpeed[1] = valSpeed;             arrSpeed[0] = (valSpeed / 2);       break;       //  Ю-В
      }                                                                          //  
  } // =======================================================================================================================================================  
  if     (flg == 10){valSpeed = 5;}                                              //  0 режим скорости
  else if(flg == 11){valSpeed = 30;}                                             //  1 режим скорости
  else if(flg == 12){valSpeed = 55;}                                             //  2 режим скорости
  else if(flg == 13){valSpeed = 80;}                                             //  3 режим скорости
  else if(flg == 14){valSpeed = 105;}                                            //  4 режим скорости
  else if(flg == 15){valSpeed = 130;}                                            //  5 режим скорости
  else if(flg == 16){valSpeed = 155;}                                            //  6 режим скорости
  else if(flg == 17){valSpeed = 180;}                                            //  7 режим скорости
  else if(flg == 18){valSpeed = 205;}                                            //  8 режим скорости
  else if(flg == 19){valSpeed = 230;}                                            //  9 режим скорости
  else if(flg == 20){valSpeed = 255;}                                            //  10 режим скорости
                                                                                 //  
  if (flg_LED) {                                                                 //  Если флаг установлен (была нажата кнопка включения фары)
    if (millis() - tmrLED > time_period) {                                       //  мигаем светодиодами с заданной частотой
      tmrLED = millis();                                                         //  сохраняем время
      digitalWrite(pinLED_RED, digitalRead(pinLED_BLUE));                        //  управляем питанием красного светодиода
      digitalWrite(pinLED_BLUE, !digitalRead(pinLED_BLUE));                      //  управляем питанием синего светодиода
      }                                                                          //  
    } else {                                                                     //  если флаг сброшен, то
      digitalWrite(pinLED_RED, LOW);                                             //  гасим светодиоды
      digitalWrite(pinLED_BLUE, LOW);                                            //  
      }                                                                          //  
  if (flgTime > millis()) {                                                      //  Если millis() переполнен, то 
    flgTime = 0;                                                                 //  сбрасываем флаг в ноль
    }                                                                            //  
// ПОДАЧА ЗНАЧЕНИЙ СКОРОСТИ И НАПРАВЛЕНИЯ ВРАЩЕНИЯ НА ВЫВОДЫ                     //  
  if (flgTime > (millis() - 500)) {                                              //  Если сигналы с телефона приходят (в течении 50 мс)
    digitalWrite(pinShield_H2, arrRoute[1]);                                     //  тогда задаем направление вращения правого мотора
    digitalWrite(pinShield_H1, arrRoute[0]);                                     //  и левого мотора
    analogWrite(pinShield_E2, arrSpeed[1]);                                      //  Задаём скорость вращения для правого мотора
    analogWrite(pinShield_E1, arrSpeed[0]);                                      //  и для левого мотора
    } else {                                                                     //  Если пакеты не приходят
    analogWrite(pinShield_E2, 0);                                                //  Останавливаем работу моторов
    analogWrite(pinShield_E1, 0);                                                //  
    }                                                                            //  
}                                                                                //  

Ссылка для скачивания эскиза

Смотрите про коптеры:  Рейтинг роботов-пылесосов: лучшие модели в 2019 году

В управлении роботом участвуют три основных этапа: получение данных с телефона; изменение значений параметров arrSpeed и arr Route; подача питания на двигатели и задание их направления. Кроме блоков переключения светодиодов, в коде есть и другие блоки: изменение скорости вращения колес; вход в режим сопряжения.

  • Получение данных с пульта:
    • Этот блок начинается с оператора if, условием которого является softSerial.available(). Это условие будет истинным, если последовательный порт получает данные от телефона, в противном случае условие будет ложным;
    • Затем следует еще один оператор while, условием которого снова является softSerial.available(). Если условие истинно, значение, поступающее на последовательный порт, будет записано в переменную str; задержка в 5 миллисекунд нужна для того, чтобы при низкой скорости передачи данных Arduino успел полностью считать значение последовательного порта в переменную str;
  • Изменение значений переменных arrSpeed, arrRoute:
    • Этот блок начинается с оператора if, при условии, что записано str == XX. В зависимости от значения XX, которое принимает переменная str (одна из 9 базовых функций), устанавливается в ноль flgTime – таймер начала выполнения функции, а также значение флага flg (от 1 до 9);
    • Далее следует конструкция switch. … case, в котором оператор switch сравнивает значение флага flg с оператором case и, в зависимости от значения флага flg, выполняет код, определяющий, какой двигатель будет запитан (переменная arrSred) и с каким направлением вращения (переменная arrRoute);
  • Подача питания на моторы и задание направления их вращения:
    • Этот блок начинается с оператора if, условием которого является flgTime > (millis() – 50). Это условие будет истинным в течение 50 миллисекунд после получения сигнала телефона и установит значения переменных arrSpeed и arrRoute на выходах Arduino. Если в течение 50 миллисекунд сигнал не поступает, значение скорости сбрасывается на 0, и робот останавливается;
  • Включение/выключение светодиодов:
    • Данный блок включает в себя 2 части: получение сигнала с телефона и изменение флага flg_LED; включение/выключение светодиодов;
    • Первая часть начинается с оператора if, в условии которого написано ( str == "SWS" || str == "SwS"). Условие будет верно, если значение переменной str будет равно SWSИЛИSwS, что приведёт к установке флага flg_LED в противоположное от нынешнего значение;
    • Вторая часть начинается с оператора if, в условии которого написано (flg_LED). Условие будет верно, если значение флага flg_LED будет true, что приведёт к включению светодиодов. Если же значение флага flg_LED будет false, то светодиоды погаснут.
  • Изменение скорости вращения колёс:
    • Это поле содержит 2 части: прием сигнала от телефона и изменение флага flg; изменение значения переменной valSpeed;
    • Первая часть начинается с оператора if, где в качестве условия записано str == XX. В зависимости от значения XX, которое принимает переменная str (одна из 11 для дополнительных функций), устанавливается значение флага flg (от 10 до 20);
    • Вторая часть начинается с оператора if, условие которого гласит, что flg == XX. В зависимости от значения XX, принимаемого переменной flg (одно из 11 для дополнительных функций), устанавливается значение переменной flg (от 5 до 255);
  • Вход в режим сопряжения (выполняется при подаче питания на робота):
    • Этот блок находится в коде void setup() и начинается с оператора if, условием которого является hc05.begin(softSerial). Это условие будет истинным, если инициализация с модулем Bluetooth через шину UART прошла успешно, о чем будет сообщено в монитор последовательного порта;
    • Затем перезапускается таймер tmrWait и проверяется условие !hc05.checkConnect() && millis().

Для работы с модулем Trema Bluetooth HC-05 необходимо использовать объект hc05 библиотеки iarduino_Bluetooth_HC05, подробности о которой можно найти в Вики – Модуль Trema Bluetooth HC-05.

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

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

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

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

Arduino. Проект «Робот-машина RoboCar4W» / Хабр

Как видите, пользоваться интерфейсом программы очень просто. В левом верхнем углу отображается индикатор соединения с модулем HC-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 тренажер включается лицом к стене. При включении перед тренажером нет препятствий – независимое движение (демо-режим).

Смотрите про коптеры:  Реактивный самолёт своими руками: «Два дебила — это сила» / Блог компании Jet Hackers / Хабр

§

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

Arduino. Проект «Робот-машина RoboCar4W» / Хабр

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

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

Arduino. Проект «Робот-машина RoboCar4W» / Хабр

Arduino. Проект «Робот-машина RoboCar4W» / Хабр

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

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(); // иначе включаем демонстрационный режим
}


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

Смотрите про коптеры:  Роботы наступают: 10 шокирующих человекоподобных роботов в мире

§

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

Когда требуются измерения статического ускорения, акселерометр ADXL345 измеряет наклон, а также динамическое ускорение, возникающее в результате движения или ударов. Благодаря высокому разрешению (4 mg/LSB) можно измерять изменения наклона менее 1 градуса.

Сборка устройства проста. Акселерометр 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);
}

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

 

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

Arduino. Проект «Робот-машина RoboCar4W» / Хабр

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

Оцените статью
Радиокоптер.ру
Добавить комментарий

Adblock
detector