Электротехника: Радиоуправление на ардуино

Электротехника: Радиоуправление на ардуино Роботы

Описание функций библиотеки:

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

  • Канал – номер от 0 до 125 определяющий частоту на которой работает модуль. Каждый канал имеет шаг в 1 МГц, а каналу 0 соответствует частота 2,4 ГГц = 2400 МГц, следовательно, каналу 1 соответствует частота 2401 МГц, каналу 2 – частота 2402 МГц и т.д. до канала 125 с частотой 2525 МГц.
  • Труба – абстрактное понятие которое можно представить как невидимая труба в которую с одной стороны отправляет данные передатчик, а с другой стороны принимает данные приёмник, при этом они никому не мешают, им никто не мешает и их «не могут» подслушать.
  • Адрес трубы – уникальный адрес позволяющий приёмнику понять, что данные назначаются именно ему, а передатчику отправлять данные для конкретного приемника. Общающимся передатчику и приемнику задаётся один и тот же адрес трубы. Адрес по умолчанию состоит из 5 байт и может быть представлен числом типа uint64_t или массивом из 5 однобайтных элементов.
  • Сеть – система обеспечивающая обмен данными между несколькими радиомодулями. Передатчик может одновременно вещать только по одной трубе, а приёмник может одновременно прослушивать до 6 труб, по этому на одном канале можно создать сеть из одного приёмника и до 6 передатчиков. Правда никто не запрещает создать на одном канале более одной сети, главное что бы не пересекались адреса их труб. Так же нужно учитывать что чем больше передатчиков находятся на одном канале и чем чаще они передают данные, тем выше вероятность «столкновения» пакетов и как следствие недоставление их адресату. На одном канале, используя одну трубу, можно создать сеть состоящую из одного передатчика и неограниченного количества приёмников. И туту тоже никто не запрещает создать на одном канале несколько таких сетей. Но в таких сетях передатчик передаёт данные сразу всем приёмникам своего канала, а подтверждение доставки данных не проверяется.
  • Номер трубы – Так как приёмник может прослушивать до 6 труб одновременно, то у приёмника каждая труба имеет не только адрес, но и номер от 0 до 5.
  • Пакет – определённым образом оформленный блок данных, передаваемый по сети. Данные между передатчиком и приемником передаются пакетами. В пакете помимо данных пользователя имеются и иные блоки (стартовые биты, адрес трубы, биты управления, CRC и т.д.).
  • Данные – до 32 байт данных пользователя передаются пакетом, где блок данных пользователя имеет статичный (по умолчанию) или динамичный размер. Если блок данных пользователя в пакете имеет динамичный размер, то чем больше байтов Вы отправляете, тем длиннее отправляемый передатчиком пакет. Если блок данных пользователя в пакете имеет статичный размер (по умолчанию), то пакет отправляемый передатчиком имеет один и тот же размер, вне зависимости от количества отправляемых Вами байт данных.
  • Ответ – пакет подтверждения приёма данных, отправляется от приёмника к передатчику. Передатчик способен запрашивать, а приёмник отправлять пакет подтверждения приёма данных. Происходит это по протоколу Enhanced Shockburst примерно так: передатчик отправляет данные приёмнику с запросом ответа, приёмник получает данные, проверяет их корректность (сверяет CRC), и если всё верно, то отвечает передатчику «Ок! я все получил, спасибо». А если приёмник не ответил передатчику, то передатчик отправляет данные приёмнику повторно, пока не исчерпает заданное количество попыток отправки данных. Но приёмник может не просто ответить передатчику, а вложить в ответ и свои данные которые примет передатчик. Таким образом можно организовать двухстороннюю связь. Блок данных в пакете подтверждения имеет динамический размер.
  • Назначение адресов туб – имеет ограничения связанные с номерами труб приёмника:
    • Труба с номером 0 используется и для чтения, и для записи. Если приёмнику указать адрес 0 трубы после чего задать роль передатчика и отправить данные, то эти данные будут отправлены по трубе с адресом который был задан приемнику как труба с номером 0. Даже если до изначально был назначен другой адрес трубы для передачи данных.
    • Адрес трубы с номером 0 может полностью отличаться от адресов труб с номерами 1-5.
    • Если адреса трубам назначаются как числа типа uint64_t, то адреса труб с номерами 2-5 должны отличаться от адреса трубы с номером 1 только последним (младшим) байтом числа.
    • Если адреса трубам назначаются как массивы, то адреса труб с номерами 2-5 должны отличаться от адреса трубы с номером 1 только первым элементом массива.
    • Трубы с номерами 0 и 1 хранят полный 5 байтовый (по умолчанию) адрес, а трубы 2-5 технически хранят только 1 байт, заимствуя 4 дополнительных байта из адреса 1 трубы, не смотря на то, что вы задаёте им полный 5 байтовый адрес. По этому нельзя открывать трубы с номерами 2-5 если не открыта труба с номером 1.
    • Размер адреса труб можно уменьшить до 4 или 3 байт, как для приёмника, так и для передатчика.
Смотрите про коптеры:  Создаем Android-приложение для управления домашним роботом через Bluetooth | CUSTOMELECTRONICS.RU

Ardu remote: очень простая и дешёвая аппаратура управления своими руками

Всем привет. Захотелось мне однажды маленькую удобную аппаратуру для дрона/крыла; usb-джойстик для симуляторов и Open.HD; найти оправдание построенной дельте (3d-принтеру) и пострадать ардуино. Сразу фото итога:

Электротехника: Радиоуправление на ардуино

Размышления и гуглеж привели к выбору BetaFPV Lite radio как образца для внешнего вида. Хотелось, конечно, Taranis X-Lite, но стики были только крупные, от подаренной товарищем бесполезной ввиду древности аппаратуры. Переключатели на 60% были использованы от неё же.
Изначально делал только USB-версию. Оно отлично работало в симуляторе FPV Freerider и как управление в Open.HD линке, но мысль прилепить QCZEK и автономное питание уже овладела мной бесповоротно.

В итоге вышло что вышло.

→ Гитхаб

Видео:

На гитхабе скетч, схема, используемые библиотеки и всякое полезное, включая 3d-модели и исходники для solid.

Схема относительно проста и требует только пайки проводов за исключением резистивного делителя и светодиодов. Работу с qczek lrs я обойду стороной, для этого есть сайт разработчика и неплохие видеотуториалы в ютубе от Юлиана и Сани areyouroo.

Электротехника: Радиоуправление на ардуино

Можно ограничиться только usb-версией без питания и lrs, в качестве lrs можно использовать другие проекты, где принимают на вход CPPM 8/10ch сигнал. При выборе QCZEK появляется выбор между 0.1 и 1вт модулями и частотами 433/868/915 МГц. Я не рекомендую 433, наводки от них дикие. Также не увидел смысла в 1вт, при 100мвт вполне реально пульнуть на 10км. Если планируете покупать антенны — смотрите на версии 915мгц и готовые антенны для популярных дальнобоек frsky. Недорого и какая-то гарантия попадания в приемлемый КСВ. Я же просто подпаял к хвосту с ipex два отрезка медной проволоки D0.4mm, длиной 8.21см и заложил это всё в корпус антенны прямо в середине печати на 3д-принтере. Побегал с аппаратурой по этажам многоквартирного дома — обрыва или падения rssi на модели в квартире не добился, устроило.

Для Open.HD (usb-версия) пока нет смысла в свичах sw4 и sw5, так как число каналов ограничено 8-ю. Возможно, в дальнейшем это ограничение будет снято. Имейте ввиду, что подключение к Open.HD с модулем зарядки даёт дополнительную нагрузку на usb-порт наземной raspberry по питанию. Имеет смысл заюзать хаб с внешним питанием.

Калибровка аппаратуры: подаём питание с зажатой SW_CALIBRATE при средних положениях yaw/roll/pitch и минимальных throttle/aux1; ждём гудка; двигаем всё с осями от минимума до максимума, пока есть пищание. Когда пищать уже не может — выключаем, калибровка завершена.

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

Каждые 30 секунд, если значения не изменились — короткий ненавязчивый писк. Естественно, все это легко изменить/отключить в скетче. Например, просто закоментировав дефайн.

В общем, заготовка для творчества вполне себе ничего. Нет триммирования, но оно и не нужно для полетов с полётным контроллером, а без него эта аппаратура врядли может пригодится.

Также я прилепил блютус-модуль jdy-30 к qczek и гоню в него мавлинк телеметрию, которую принимает DroidPlanner 2.8 или Telemetry Viewaver на андроид-смартфоне. Наверное, также засуну и mavlink-display. Пусть будет красиво, как у дорогих crossfire xD

Спасибо за внимание, жду вопросов и повторений / развитий сего рукожопства.

Двунаправленная отправка данных:

Модуль может работать либо в режиме передатчика, либо в режиме приёмника, но передатчик способен запрашивать, а приёмник отправлять пакет подтверждения приёма данных. Происходит это по протоколу Enhanced Shockburst примерно так: передатчик отправляет данные приёмнику с запросом ответа, приёмник получает данные, проверяет их корректность (сверяет CRC), и если всё верно, то отвечает передатчику «Ок! я все получил, спасибо.».

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

Скетч приёмника:

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS).
int      myData[5];                                            // Объявляем массив для приёма и хранения данных (до 32 байт включительно).
int      ackData[5];                                           // Объявляем массив для передачи данных в пакете подтверждения приёма (до 32 байт включительно).
                                                               //
void setup(){                                                  //
    radio.begin();                                             // Инициируем работу nRF24L01 
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит передача данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.enableAckPayload();                                  // Указываем что в пакетах подтверждения приёма есть блок с пользовательскими данными.
//  radio.enableDynamicPayloads();                             // Разрешить динамически изменяемый размер блока данных на всех трубах.
    radio.openReadingPipe (1, 0xAABBCCDD11LL);                 // Открываем 1 трубу с адресом 0xAABBCCDD11, для приема данных.
    radio.startListening  ();                                  // Включаем приемник, начинаем прослушивать открытые трубы.
    radio.writeAckPayload (1, &ackData, sizeof(ackData) );     // Помещаем данные всего массива ackData в буфер FIFO. Как только будут получены любые данные от передатчика на 1 трубе, то данные из буфера FIFO будут отправлены этому передатчику вместе с пакетом подтверждения приёма его данных.
}                                                              // В модуле имеется 3 буфера FIFO, значит в них одновременно может находиться до трёх разных или одинаковых данных для ответа по одной или разным трубам.
                                                               // После отправки данных из буфера FIFO к передатчику, соответствующий буфер очищается и способен принять новые данные для отправки.
void loop(){                                                   //
    if(radio.available()){                                     // Если в буфере приёма имеются принятые данные от передатчика, то ...
        radio.read            (   &myData,  sizeof(myData)  ); // Читаем данные из буфера приёма в массив myData указывая сколько всего байт может поместиться в массив.
        radio.writeAckPayload (1, &ackData, sizeof(ackData) ); // Помещаем данные всего массива ackData в буфер FIFO для их отправки на следующее получение данных от передатчика на 1 трубе.
    }                                                          // Если все 3 буфера FIFO уже заполнены, то функция writeAckPayload() будет проигнорирована.
}                                                              // Так как в данном скетче данные в буфер помещаются только после получения данных от передатчика, значит один из буферов был только что очищен и заполнение всех 3 буферов в данном скетче невозможно.

Обратите внимание на то, что ответ приёмника ackData сначала помещается в буфер FIFO функцией writeAckPayload(), а отправляется он аппаратно, при получении данных от передатчика, но ещё до того как функция available() вернёт true.

Скетч передатчика:

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS)
int      myData[5];                                            // Объявляем массив для хранения и передачи данных.
int      ackData[5];                                           // Объявляем массив для получения данных из пакета подтверждения приёма (до 32 байт включительно).
                                                               //
void setup(){                                                  //
    radio.begin           ();                                  // Инициируем работу модуля nRF24L01 .
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит передача данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.enableAckPayload();                                  // Указываем что в пакетах подтверждения приёма есть блок с пользовательскими данными.
//  radio.enableDynamicPayloads();                             // Разрешить динамически изменяемый размер блока данных на всех трубах.
    radio.openWritingPipe (0xAABBCCDD11LL);                    // Открываем трубу с адресом 0xAABBCCDD11 для передачи данных (передатчик может одновременно вещать только по одной трубе).
}                                                              //
                                                               //
void loop(){                                                   //
    radio.write(&myData, sizeof(myData));                      // Отправляем данные из массива myData указывая сколько байт массива мы хотим отправить.
    if( radio.isAckPayloadAvailable() ){                       // Если в буфере имеются принятые данные из пакета подтверждения приёма, то ...
        radio.read(&ackData, sizeof(ackData));                 // Читаем данные из буфера в массив ackData указывая сколько всего байт может поместиться в массив.
    }                                                          //
    delay(50);                                                 // Устанавливаем задержку на 50 мс. В этом скетче нет смысла слать данные чаще.
}                                                              //

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

Стоит отметить несколько особенностей данной реализации связи:

  • На стороне передатчика, вместо функции isAckPayloadAvailable() можно использовать функцию available(), она будет работать точно так же.
  • Блоки данных в пакетах подтверждения приёма имеют динамически изменяемый размер, он используется по умолчанию для отправки ответов по трубам 0 и 1, так что если данные приемника нужно отправить передатчику по трубам 2-5 (где по умолчанию используются статичный размер ответных данных), то необходимо раскомментировать функцию enableDynamicPayloads() в обоих скетчах.
  • Если на стороне передатчика не читать данные из буферов, то буферы заполнятся и перестанут принимать пакеты подтверждения приёма, тогда функция write() будет всегда возвращать false, хотя данные будут и отправляться, и приниматься приемниками.
  • Если на стороне приемника формировать ответы для нескольких передатчиков (а каждый из них должен использовать свою трубу), то нужно учитывать тот факт что у модуля для этих целей имеется всего 3 буфера, которые могут хранить до трех ответов для труб с разными или одинаковыми номерами. Если буферы заполнены, то функция writeAckPayload() будет проигнорирована. Например, если в буферах уже есть ответы для труб с номерами 1,2 и 3, новые ответы записать не получится, а пришли данные от передатчика по трубе с номером 0, то он естественно не получит ответ.

Передача данных нескольким приёмникам:

В некоторых случаях может возникнуть необходимость отправки данных от одного передатчика к нескольким приёмникам, это можно сделать, но каждый приёмник будет отправлять передатчику пакеты подтверждения приёма. Эти пакеты будут отправляться почти одновременно и как следствие неизбежно «перемешаются / столкнутся».

Представленный ниже скетч передатчика отправляет данные приёмникам не запрашивая у них пакеты подтверждения приёма, так как функция write() вызывается с установленным флагом групповой передачи данных (третий параметр функции). Стоит отметить что и в коде setup() было обращение к функции enableDynamicAck(), без которой функция write() будет игнорировать флаг групповой передачи данных.

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS)
int      myData[5];                                            // Объявляем массив для хранения и передачи данных.
                                                               //
void setup(){                                                  //
    radio.begin           ();                                  // Инициируем работу модуля nRF24L01 .
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит передача данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.enableDynamicAck();                                  // Разрешаем выборочно отключать запросы подтверждения приема данных.
    radio.openWritingPipe (0xAABBCCDD11LL);                    // Открываем трубу с адресом 0xAABBCCDD11 для передачи данных (передатчик может одновременно вещать только по одной трубе).
}                                                              //
                                                               //
void loop(){                                                   //
    radio.write(&myData, sizeof(myData), true);                // Отправляем данные из массива myData указывая сколько байт массива мы хотим отправить и устанавливаем флаг групповой передачи данных.
    delay(50);                                                 // Устанавливаем задержку на 50 мс. В этом скетче нет смысла слать данные чаще.
}                                                              // Так же задержка нужна для того, что бы приёмники успели выполнить свои действия над полученными данными (если таковые необходимы) до следующей передачи.

Такой передатчик способен отправить данные сразу нескольким приёмникам на одном канале и по одной трубе. Корректность доставки данных по прежнему будет проверяться на стороне приемников путём сравнения CRC, но сам факт доставки данных проверить не получится, так как функция write() на стороне передатчика будет постоянно возвращать true, вне зависимости от того доставлены данные или нет.

Запретить отправку пакетов подтверждения приёма можно и на стороне приёмников, вызвав у них функцию setAutoAck( false ) или setAutoAck( номер трубы, false ). Но в таком случае и на стороне передатчика нужно вызвать функцию setAutoAck( false ) иначе приёмник не будет понимать что ему прислал передатчик.

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

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

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

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

Пример передачи данных:

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS).
int      myData[5];                                            // Объявляем массив для хранения и передачи данных (до 32 байт включительно).
                                                               //
void setup(){                                                  //
    radio.begin           ();                                  // Инициируем работу модуля nRF24L01 .
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит передача данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем уровень усиления передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.openWritingPipe (0xAABBCCDD11LL);                    // Открываем трубу с адресом 0xAABBCCDD11 для передачи данных (передатчик может одновременно вещать только по одной трубе).
}                                                              //
                                                               //
void loop(){                                                   //
    radio.write( &myData , sizeof(myData) );                   // Отправляем данные из массива myData указывая весь размер массива в байтах.
    delay(50);                                                 // Устанавливаем задержку на 50 мс. В этом скетче нет смысла слать данные чаще.
}                                                              // Так же задержка нужна для того, что бы приёмник успел выполнить свои действия над полученными данными (если таковые необходимы) до следующей передачи.

Скетч данного примера начинается с подключения файлов библиотек SPI, RF24 и файла настроек nRF24L01. Далее создаётся объект radio с указанием выводов Arduino к которым подключены выводы модуля CE (Chip Enable)

и SS (Slave Select). Можно указать любые выводы Arduino, но какие выводы Вы укажите, к тем выводам и следует подключать модуль. Далее в скетче объявляется массив myData из 5 элементов типа int, данные которого и будут передаваться.

В коде setup() данного примера модулю задаются основные настройки: модуль работает в качестве передатчика (по умолчанию), на 27 канале, со скоростью 1 Мбит/сек (RF24_1MBPS), на максимальной мощности (RF24_PA_MAX), используя адрес трубы 0xAABBCCDD11. На стороне приёмника нужно указать тот же номер канала, скорость передачи, мощность и адрес трубы.

В коде loop() осуществляется отправка данных функцией write( данные , размер ). В качестве данных для передачи указан адрес массива в памяти ОЗУ &myData, а в качестве размера передаваемых данных указан размер всего массива в байтах sizeof(myData). Размер передаваемых данных указывается в байтах, а не в количестве элементов массива.

Если требуется отправить не весь массив myData а, например, его первые три элемента, то строку отправки данных можно было бы записать так radio.write( &myData , 6 ); – отправить первые 3 элемента типа int (6 байт) массива myData.

Пример получения данных от одного или нескольких передатчиков:

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS).
int      myData[5];                                            // Объявляем массив для приёма и хранения данных (до 32 байт включительно).
uint8_t  pipe;                                                 // Объявляем переменную в которую будет сохраняться номер трубы по которой приняты данные.
                                                               //
void setup(){                                                  //
    radio.begin();                                             // Инициируем работу nRF24L01 .
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит приём данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.openReadingPipe (1, 0xAABBCCDD11LL);                 // Открываем 1 трубу с адресом 1 передатчика 0xAABBCCDD11, для приема данных.
    radio.openReadingPipe (2, 0xAABBCCDD22LL);                 // Открываем 2 трубу с адресом 2 передатчика 0xAABBCCDD22, для приема данных.
    radio.openReadingPipe (3, 0xAABBCCDD33LL);                 // Открываем 3 трубу с адресом 3 передатчика 0xAABBCCDD33, для приема данных.
    radio.openReadingPipe (4, 0xAABBCCDD96LL);                 // Открываем 4 трубу с адресом 4 передатчика 0xAABBCCDD96, для приема данных.
    radio.openReadingPipe (5, 0xAABBCCDDFFLL);                 // Открываем 5 трубу с адресом 5 передатчика 0xAABBCCDDFF, для приема данных.
    radio.startListening  ();                                  // Включаем приемник, начинаем прослушивать открытые трубы.
}                                                              //
                                                               //
void loop(){                                                   //
    if(radio.available(&pipe)){                                // Если в буфере имеются принятые данные, то получаем номер трубы по которой эти данные пришли в переменную pipe.
        radio.read( &myData, sizeof(myData) );                 // Читаем данные из буфера в массив myData указывая сколько всего байт может поместиться в массив.
        if(pipe==1){ /* Данные пришли по 1 трубе */ ;}         // Если данные пришли от 1 передатчика (по 1 трубе), то можно выполнить соответствующее действие ...
        if(pipe==2){ /* Данные пришли по 2 трубе */ ;}         // Если данные пришли от 2 передатчика (по 2 трубе), то можно выполнить соответствующее действие ...
        if(pipe==3){ /* Данные пришли по 3 трубе */ ;}         // Если данные пришли от 3 передатчика (по 3 трубе), то можно выполнить соответствующее действие ...
        if(pipe==4){ /* Данные пришли по 4 трубе */ ;}         // Если данные пришли от 4 передатчика (по 4 трубе), то можно выполнить соответствующее действие ...
    }                                                          //
}                                                              //

Скетч приёмника начинается как и два предыдущих скетча передатчиков (подключаются библиотеки, создаётся объект, объявляется массив), но еще объявляется переменная pipe.

В коде setup() модулю задаются такие же настройки как и передатчику (27 канал, скорость 1 Мбит/сек, максимальная мощность передатчика). Тут стоит вспомнить про то, что приемник по умолчанию отправляет передатчику пакеты подтверждения приёма, а следовательно модулю выполняющему роль приёмника приходится указывать мощность передатчика (ведь если пакеты подтверждения от приёмника к передатчику будут отправляться с меньшей мощностью, то передатчик их может и не получить).

Далее, в отличии от передатчика которому был задан один адрес трубы функцией openWritingPipe(), приёмнику можно задать до 6 труб функцией openReadingPipe( номер , адрес) с номерами труб от 0 до 5 и адресами труб совпадающими с адресами труб передатчиков.

Сколько труб Вы укажете, столько передатчиков будет слушать приёмник. И последняя функция которая вызвана в данном коде – startListening() включающая прослушивание труб, то есть переводящая модуль в режим работы приемника. Если далее вызвать функцию stopListening()- завершить прослушивание труб, то модуль перейдёт в режим работы передатчика.

В коде loop() осуществляется проверка получения данных функцией available(), которая возвращает true если в буфере есть принятые данные доступные для чтения. В качестве необязательного аргумента функции available() можно указать адрес переменной в которую будет помещён номер трубы по которой были приняты данные (в примере используется адрес переменной &pipe).

Зная номер трубы мы знаем от какого передатчика пришли данные. Данные из буфера читаются функцией read( адрес массива для данных , размер ), в примере указан адрес ОЗУ массива &myData, а в качестве размера указывается размер массива sizeof(myData) в байтах, а не размер принимаемых данных.

Если приемник будет принимать данные только от одного передатчика, то объявлять переменную pipe в начале скетча не надо, функцию openReadingPipe() достаточно вызвать один раз (указав номер от 0 до 5 и адрес трубы передатчика), а функцию available() можно вызвать без параметра, так как в этом случае не требуется узнавать от какого передатчика приняты данные.

Пример ретрансляторов:

Ретранслятор это устройство с приемником и передатчиком, в котором все что принял приемник передаётся на передатчик. Чаще всего ретрансляторы применяют для увеличения дальности передачи данных. Если модуль рассчитан на дальность в 1 км, то расстояние между приёмником и передатчиком не должно превышать указанного расстояния.

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS)
int      myData[5];                                            // Объявляем массив для приёма, хранения и передачи данных (до 32 байт включительно).
                                                               //
void setup(){                                                  //
    radio.begin();                                             // Инициируем работу nRF24L01 
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит передача данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.openReadingPipe (1, 0xFEDCBA9876LL);                 // Открываем 1 трубу с адресом 0xFEDCBA9876 для приема   данных.
    radio.openWritingPipe (   0xAABBCCDD11LL);                 // Открываем   трубу с адресом 0xAABBCCDD11 для передачи данных (передатчик может одновременно вещать только по одной трубе).
    radio.startListening  ();                                  // Включаем приемник, начинаем прослушивать открытые трубы.
}                                                              //
                                                               //
void loop(){                                                   //
    if( radio.available() ){                                   // Если в буфере имеются принятые данные, то ...
        radio.read           (&myData, sizeof(myData) );       // Читаем данные из буфера в массив myData указывая сколько всего байт может поместиться в массив.
        radio.stopListening  ();                               // Выключаем приемник, завершаем прослушивание открытых труб.
        radio.write          (&myData, sizeof(myData) );       // Отправляем данные из массива myData указывая сколько байт массива мы хотим отправить.
        radio.startListening ();                               // Включаем приемник, начинаем прослушивать открытые трубы.
    }                                                          //
}                                                              //

В коде setup() данного примера модулю задаются основные настройки: модуль работает на 27 канале, со скоростью 1 Мбит/сек (RF24_1MBPS), на максимальной мощности (RF24_PA_MAX). Далее модулю присваиваются два адреса труб:

Алгоритм кода loop() заключается в том, что как только модуль получает данные if(radio.available()){…}, они читаются функцией read() в массив myData, далее модуль завершает прослушивание труб stopListening(), отправляет все полученные данные функцией write() и вновь начинает прослушивание труб startListening().

Таким образом устройство с данным скетчем является приёмопередатчиком и может стать посредником между передатчиком, отправляющим данные по трубе с адресом 0xFEDCBA9876 и приёмником прослушивающим трубу с адресом 0xAABBCCDD11, при этом все устройства работают на одной частоте (27 канал), с одной и той же скоростью (1 Мбит/сек) и мощностью.

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

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI.
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24.
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01 .
RF24     radio(7, 10);                                         // Создаём объект radio для работы с библиотекой RF24, указывая номера выводов модуля (CE, SS)
int      myData[5];                                            // Объявляем массив для приёма, хранения и передачи данных (до 32 байт включительно).
                                                               //
void setup(){                                                  //
    radio.begin();                                             // Инициируем работу nRF24L01 .
    radio.setChannel      (27);                                // Указываем канал передачи данных (от 0 до 125), 27 - значит приём данных осуществляется на частоте 2,427 ГГц.
    radio.setDataRate     (RF24_1MBPS);                        // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек.
    radio.setPALevel      (RF24_PA_MAX);                       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm).
    radio.openReadingPipe (0, 0xAABBCCDD11LL);                 // Открываем 0 трубу с адресом 0xAABBCCDD11, для приема и передачи данных.
    radio.startListening  ();                                  // Включаем приемник, начинаем прослушивать открытые трубы.
}                                                              //
                                                               //
void loop(){                                                   //
    if(radio.available()){                                     // Если в буфере имеются принятые данные, то ...
        radio.read            ( &myData, sizeof(myData) );     // Читаем данные из буфера в массив myData указывая сколько всего байт может поместиться в массив.
        radio.stopListening   ();                              // Выключаем приёмник, завершаем прослушивание открытых труб.
        radio.setChannel      (29);                            // Указываем канал передачи данных (от 0 до 125), 29 - значит передача данных осуществляется на частоте 2,429 ГГц.
        radio.write           ( &myData, sizeof(myData) );     // Отправляем данные из массива myData указывая весь размер массива в байтах.
        radio.setChannel      (27);                            // Указываем канал передачи данных (от 0 до 125), 27 - значит приём данных осуществляется на частоте 2,427 ГГц.
        radio.startListening  ();                              // Включаем приемник, начинаем прослушивать открытые трубы.
    }                                                          //
}                                                              //

В коде setup() данного примера, функцией openReadingPipe(), модулю была указана труба для приёма данных с номером 0 и адресом 0xAABBCCDD11. Адрес трубы с номером 0 (в отличии от труб с номерами 1-5) применяется как для приёма, так и для передачи данных, по этому функция openWritingPipe() в данном коде не участвует.

Алгоритм кода loop() аналогичен предыдущему скетчу, за исключением того, что для передачи данных модуль использует 29 канал, а для приёма 27. Не рекомендуется использовать соседние каналы (27 и 28, или 28 и 29, и т.д.) для работы с одинаковыми адресами труб.

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

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

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

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

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

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

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

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

Для добавления контроллера разряда придется внести следующие изменения в схему:

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

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

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

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

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