понедельник, 21 сентября 2015 г.

Машинка на радиоуправлении своими руками.

Наиболее просто реализовать радиоуправление самодельной машинкой, при этом делая что либо самостоятельно, можно используя радиомодули NRF24L01+ (можно заказать по ссылке), плату Ардуино например Arduino UNO (купить по ссылке) (или любую другую Ардуино или подобную плату). Также понадобятся драйверы для управления двигателями, можно использовать например L293D если двигатели потребляют ток до 600мА, сами двигатели, батарейки и некоторые дополнительные элементы. В рулевой системе машинки можно установить такой же линейный актуатор с шаговым двигателем которые используются в дисководах. Механика рулевой системы должна быть такой чтобы не было необходимости в большой силе двигателя для того чтобы осуществить поворот. Если поворот осуществляется достаточно легко то можно сделать полношаговое управление двигателем с использованием одной фазы на каждом шаге, если при всех стараниях не получилось сделать достаточно легко поворачивающиеся передние колёса то для решения проблемы поворота можно сделать полношаговое управление с использованием двух фаз на каждом шаге и немного увеличить напряжение питания при этом увеличиться момент и потребление тока в следствии чего батарейки будут быстрее разряжаться но зато рулевая система будет более надёжной. Для движения вперёд и назад можно использовать любой подходящий и достаточно мощный коллекторный электродвигатель постоянного тока в котором реверс осуществляется сменой полярности подаваемого на него напряжения. У большинства таких двигателей обороты слишком большие и момент слишком мал для того чтобы можно было использовать прямую передачу на колёса без редуктора (например надев колесо на вал двигателя). Редуктор можно использовать готовый или изготовить самостоятельно. Если редуктор изготавливается самостоятельно но необходимо уделить достаточно внимания его изготовлению и по возможности избежать фрикционных и ремённых передач а делать только с шестерёнками, если этого не получилось то ремённые или фрикционные передачи необходимо делать очень качественно. При изготовлении механических частей машинки для скрепления частей можно использовать цианоакрилатный клей (например клей (можно заказать по ссылке) ) т.к. он достаточно прочно держит любые поверхности и быстро твердеет (такие клея твердеют не от высыхания а от контакта с влажными поверхностями (полимеризацию вызывает щелочная среда)). Простота изготовления электроники позволяет сосредоточиться на механике но давайте всё же рассмотрим схему приёмника:
Рисунок 1 - Приёмник

Радиомодуль NRF24L01+ взаимодействует с платой Arduino через интерфейс SPI. Питание 3.3В на радиомодуль идёт с платы Arduino (в плате есть стабилизатор напряжения). На саму плату Ардуино подаётся 9В от 6ти пальчиковых батареек соединённых последовательно. Это питание следует подавать через специальный разъём (понятно из рисунка 1). На плате есть стабилизатор на 5В. Между выводом GND и +3.3В радиомодуляNRF24L01+ стоит конденсатор для сглаживания пульсаций напряжения которые могут появляться например при работе двигателей. Драйверы запитываются непосредственно от батареек, один из драйверов целиком используется для управления шаговым двигателем, другой для управления коллекторным, светодиодными фонарями и пьезодинамиком. Пьезодинамик можно поставить на тот же полумост драйвера что и фонари т.к. он издаёт звуки только от переменного напряжения. Скетч в Ардуино загружается при отключенном питании. Давайте рассмотрим скетч:

#include "SPI.h"
#include "nRF24L01.h"
#include "RF24.h"

RF24 radio(9,10);

const uint64_t pipe = 0xF0F0F0F0E1LL;

char data = 'z';
char data_turning = 's';
//20 binary 00010100
//24 binary 00011000
//40 binary 00101000
//36 binary 00100100
unsigned char arr[4]={20,24,40,36};
unsigned char counter = 0;
unsigned char out_condit = 0;
unsigned char out_going = 0;
void stepper_rotate()
{
             if (data_turning == 'l')
             {
               counter++;
               if(counter3)counter=0;
               out_condit = arr[counter];
             }
             else if (data_turning == 'r')
             {
                if(counter==0)
                {
                    out_condit = arr[0];
                    counter=3;
                }
                else
                {
                    out_condit = arr[counter];
                    counter--;
                }
             }
             else if(data_turning == 's')
             {
             out_condit = 0;
             }
}
void bebep()
{
      for(int i=0;i5000;i++)  
     {
        digitalWrite(8, HIGH);
        delayMicroseconds(100);
        digitalWrite(8, LOW);
        delayMicroseconds(100);
      }
}
void setup(void)
{
  radio.begin();
  radio.setRetries(15,15);
  radio.openReadingPipe(1,pipe);
  radio.startListening();
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
}

void loop(void)
{
  if ( radio.available() )
  {
    radio.read( &data, sizeof(char) );
    switch(data)
    {
      //мотор
      case 'a':
        out_going = 128;
      break;
      case 'b':
        out_going = 64;
      break;
      case 'c':
        out_going = 0;
      break;
      //фары
      case 'd':
        digitalWrite(8, HIGH);
      break;
      case 'e':
        digitalWrite(8, LOW);
      break;
      //гудок
      case 'f':
        bebep();
      break;
      //руль
      case 'r':
        data_turning = 'r';
      break;
      case 'l':
        data_turning = 'l';
      break;
      case 's':
        data_turning = 's';
      break;
    }
  }
    //руль
    stepper_rotate();
    PORTD &= 195;//binary 11000011
    PORTD |= out_condit;
    //мотор
    PORTD &= 63;//binary 00111111
    PORTD |= out_going;
 
    delay(12);
}

Это скетч для приёмника, в первых трёх строчках этого скетча подключаются заголовочные файлы для простой реализации связи по SPI и использования радиомодуля NRF24L01+. Следующая строка - это создание экземпляра класса "RF24", первым параметром в конструктор этого класса передаётся номер пина Ардуино который следует соединить с CE радиомодуля а вторым параметром - номер пина который следует соединить с CSN радиомодуля. Следующая строка - это адрес канала, он должен быть одинаковым у приёмника и передатчика. Далее идёт инициализация переменных. В переменную "data" записывается принятый по радио символ. В переменную "data_turning" записывается символ который определяет будет ли вращаться ротор шагового двигателя рулевой системы и если да то в какую сторону. Далее идёт массив состояний порта для управления шаговым двигателем. Переменная "counter" вспомогательная для функции управления шаговым двигателем. Дальше идёт функция управления шаговым двигателем "stepper_rotate()" после неё идёт функция создания гудка "bebep()". В функции "setap" происходит инициализация радиомодуля и выводов Ардуино. В функции "loop" принимается символ и в соответствии с принятым символом совершаются определённые действия.
Передатчик можно изготовить на любом Ардуино. Рассмотрим схему передатчика:
Рисунок 2 - Передатчик

У каждого Arduino есть выводы SPI но обычно на плате они не подписаны, выяснить где эти выводы находятся можно из документации на конкретное Arduino. На рисунке 2 показан джойстик, джойстик обычно можно представить в виде набора кнопок. Если соответствующая кнопка нажата то на соответствующем выводе Arduino появиться низкое напряжение (логический ноль), если кнопка не нажата то на выводе будет высокое напряжение (логическая единица) т.к. этот вывод соединён с +5В через резистор с сопротивлением 10кОм (можно использовать резистор с другим близким к 10кОм сопротивлением) эти +5В берутся с вывода Ардуино. Ардуино можно питать одной батарейкой "Крона" на 9В, это питание также подаётся на Arduino через специальный разъём. Скетч также загружается при отключенном питании. Скетч для передатчика:


#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

RF24 radio(9,10);

const uint64_t pipe = 0xF0F0F0F0E1LL;
char data='a';

boolean but_forward_before;
boolean but_forward;
boolean but_back_before;
boolean but_back;
boolean but_left_before;
boolean but_left;
boolean but_right_before;
boolean but_right;
boolean but_fire_before;
boolean but_fire;

void sendData()
{
     radio.openWritingPipe(pipe);
     radio.startListening();
     radio.write( &data, sizeof(char) );
     delay(20);
}

void setup(void)
{
  //Serial.begin(57600);
  radio.begin();
  radio.setRetries(15,15);
  radio.openWritingPipe(pipe);
  radio.startListening();
  //установки для кнопок
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  pinMode(3, INPUT);
  digitalWrite(3, HIGH);
  pinMode(4, INPUT);
  digitalWrite(4, HIGH);
  pinMode(5, INPUT);
  digitalWrite(5, HIGH);
  pinMode(6, INPUT);
  digitalWrite(6, HIGH);
}

void loop(void)
{
   but_forward = digitalRead(2);
   but_back = digitalRead(3);
   but_left = digitalRead(4);
   but_right = digitalRead(5);
   but_fire = digitalRead(6);
 
   if(but_forward_before && !but_forward)
   {
     data = 'a';
     sendData();
   }
   else if(but_back_before && !but_back)
   {
     data = 'b';
     sendData();
   }
   else if((!but_forward_before && but_forward) || (!but_back_before && but_back))
   {
     data = 'c';
     sendData();
   }
   if(but_left_before && !but_left)
   {
     data = 'l';
     sendData();
   }
   else if(but_right_before && !but_right)
   {
     data = 'r';
     sendData();
   }
   else if((!but_left_before && but_left) || (!but_right_before && but_right))
   {
     data = 's';
     sendData();
   }
   if(but_fire_before && !but_fire)
   {
     data = 'f';
     sendData();
   }
 
   but_forward_before = but_forward;
   but_back_before = but_back;
   but_left_before = but_left;
   but_right_before = but_right;
   but_fire_before = but_fire;
   delay(80);
}

Первые 6 строчек аналогичны тем что в скетче для приёмника, далее идут переменные которые используются для хранения текущих и предыдущих состояний кнопок джойстика. Функция "sendData()" отсылает символ который записан в переменной "data". В функции "setup" происходит инициализация радиомодуля и настройка необходимых выводов. В функции "loop" происходит отправка символа для движения вперёд если кнопка "вперёд" переходит из не нажатого состояния в нажатое, если тоже самое происходит в кнопкой "назад" то отсылается символ для движения машинки назад, если кнопка "вперёд" переходит из нажатого состояния в ненажатое или кнопка "назад" переходит из нажатого состояния в не нажатое то отправляется символ для остановки машинки, аналогично и для рулевой системы, есть ещё символ для гудка и он отправляется если кнопка "гудок" переходит из не нажатого состояния в нажатое. В общем скетчи достаточно простые, скачать их можно по ссылке: https://yadi.sk/d/K0HfKwcojCuaX.
Корпус лучше сделать из картона т.к. он не мешает прохождению радиосигнала, к тому же его можно красиво раскрасить:
Процесс сборки (неполный и ускоренный для экономии времени) машинки с некоторыми комментариями а также демонстрацию работы можно увидеть на видео:

КАРТА БЛОГА (содержание)