пятница, 16 октября 2015 г.

Дистанционно управляемая машинка

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


Видео.


Про саму платформу я уже рассказывал ранее. Здесь скажу лишь пару слов. Два коллекторных моторчика с редукторами. Три колеса. По колесику на мотор-редуктор и одно опорное. У меня платформа самодельная, но можно купить готовую.


Единственное я бы рекомендовал поискать платформы с мотор-редукторами помедленнее. Такие платформы лучше подходят для обучения. Для высоких скоростей существуют другие решения.

Мозгом платформы является arduino nano.


Для удобства подключения используется arduino nano sensor shield.


Драйвер двигателей на L9110S.


И приемник.


Соединяется всё согласно изложенным ниже инструкциям.

Левый двигатель подключаются к клеммам MOTOR-A. Правый двигатель подключается к клеммам MOTOR-B. Какая клемма мотора с какой клеммой драйвера соединяется, нужно определять опытным путем.

Arduino --- Motor Driver
GND --- GND
VCC --- VCC
D8 --- B-IB
D9 --- B-IA
D10 --- A-IB
D11 --- A-IA

Arduino Nano --- IR Receiver
GND --- GND
VCC --- VCC
D2 --- OUT

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

Основой пульта также является arduino nano.


Модуль с кнопочками.


ИК передатчик.


Схема.



Этот ИК передатчик обеспечивает связь на пару метров. Но есть и более дальнобойная версия.


Схема.


По расстоянию ничего конкретного сказать не могу. Нет у меня такого модуля. Без сомнений оно больше, но насколько...

Есть ещё одна модификация ИК передатчика.


Схема.


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

При наличии желания можно самостоятельно сделать довольно мощный ИК передатчик.


Резистор R2 можно взять и поменьше. На 22 Ом. В любом случае он должен быть достаточно мощным. Минимум 1 Вт. R1 и R3 достаточно 0.25 Вт. Включать этот модуль можно лишь в импульсном режиме.

Ниже приводятся инструкции по соединению модулей.

Arduino --- Button module
A0 --- SW1
A1 --- SW2
A2 --- SW3
A4 --- SW4
VCC --- VCC
GND --- GND

Arduino --- IR led module
D8 --- DAT
VCC --- VCC
GND --- GND

У меня пульт питается через USB разъем. Но ничто не мешает запитать его от тех же четырех аккумуляторов NiMH.

Скетч для платформы.

////////////////////////
//
// Arduino Nano
//
////////////////////////
//
// Sketch: IR receiver
//

const unsigned char A_IA = 8;
const unsigned char A_IB = 9;
const unsigned char B_IA = 10;
const unsigned char B_IB = 11;

const unsigned long int CODE1 = 0b10000001;
const unsigned long int CODE2 = 0b10000010;
const unsigned long int CODE3 = 0b10000100;
const unsigned long int CODE4 = 0b10001000;
const unsigned long int CODE5 = 0b10010000;
const unsigned long int CODE6 = 0b10100000;

volatile unsigned char data = 0;
volatile unsigned char temp = 0;
volatile unsigned char count = 0;
volatile unsigned long int time1 = 0;
volatile unsigned long int time2 = 0;
volatile unsigned long int period = 0;

void forward_forward( void )
{
    digitalWrite(A_IA, HIGH);
    digitalWrite(A_IB, LOW);
    digitalWrite(B_IA, HIGH);
    digitalWrite(B_IB, LOW);
}

void backward_backward( void )
{
    digitalWrite(A_IA, LOW);
    digitalWrite(A_IB, HIGH);
    digitalWrite(B_IA, LOW);
    digitalWrite(B_IB, HIGH);
}

void forward_stop( void )
{
    digitalWrite(A_IA, HIGH);
    digitalWrite(A_IB, LOW);
    digitalWrite(B_IA, LOW);
    digitalWrite(B_IB, LOW);
}

void stop_forward( void )
{
    digitalWrite(A_IA, LOW);
    digitalWrite(A_IB, LOW);
    digitalWrite(B_IA, HIGH);
    digitalWrite(B_IB, LOW);
}

void backward_stop( void )
{
    digitalWrite(A_IA, LOW);
    digitalWrite(A_IB, HIGH);
    digitalWrite(B_IA, LOW);
    digitalWrite(B_IB, LOW);
}

void stop_backward( void )
{
    digitalWrite(A_IA, LOW);
    digitalWrite(A_IB, LOW);
    digitalWrite(B_IA, LOW);
    digitalWrite(B_IB, HIGH);
}

void stop_stop( void )
{
    digitalWrite(A_IA, LOW);
    digitalWrite(A_IB, LOW);
    digitalWrite(B_IA, LOW);
    digitalWrite(B_IB, LOW);
}

void setup()
{
    attachInterrupt(0, tsop, FALLING);

    pinMode(A_IA, OUTPUT);
    pinMode(A_IB, OUTPUT);
    pinMode(B_IA, OUTPUT);
    pinMode(B_IB, OUTPUT);

    stop_stop();
}

void loop()
{
    if ( data == CODE1 ) forward_stop();
    if ( data == CODE2 ) backward_stop();
    if ( data == CODE3 ) stop_backward();
    if ( data == CODE4 ) stop_forward();
    if ( data == CODE5 ) forward_forward();
    if ( data == CODE6 ) backward_backward();
    if ( data == 0 ) stop_stop();

    data = 0;
    delay(70);
}

void tsop()
{
    time1 = micros();
    period = time1 - time2;
    time2 = time1;

    temp <<= 1;
    count += 1;

    if ( period > 1500 ) temp |= 1;
    if ( period > 15000 ) count = 0;
    if ( count == 8 ) data = temp;
}

//
// End
//
////////////////////////

Скетч для пульта.

////////////////////////
//
// Arduino Nano
//
////////////////////////
//
// Sketch: IR transmitter
//

// Arduino --- IR led module
// D8 --- DAT
// VCC --- VCC
// GND --- GND

// Arduino --- Button module
// A0 --- SW1
// A1 --- SW2
// A2 --- SW3
// A4 --- SW4
// VCC --- VCC
// GND --- GND

#include <util/delay.h>

const unsigned char CODE1 = 0b10000001;
const unsigned char CODE2 = 0b10000010;
const unsigned char CODE3 = 0b10000100;
const unsigned char CODE4 = 0b10001000;
const unsigned char CODE5 = 0b10010000;
const unsigned char CODE6 = 0b10100000;

volatile unsigned char count = 0;

void IR_send( unsigned char data )
{
    for (char i=0; i<=8; i++)
    {
        TCCR2B = (1<<CS20);

        if ( (data & 0b10000000) != 0 )
            while ( count < 152 );

        if ( (data & 0b10000000) == 0 )
            while ( count < 76 );

        TCCR2B = 0;

        data <<= 1;

        count = 0;
    }

    _delay_ms(23); // wait 23 ms
}

// Input/Output Ports initialization
void Ports_Init( void )
{
    // Port B initialization
    // - - PB5 PB4 PB3 PB2 PB1 PB0
    DDRB = 0b00000001;
    PORTB = 0b00000000;

    // Port C initialization
    // - - PC5 PC4 PC3 PC2 PC1 PC0
    DDRC = 0b00000000;
    PORTC = 0b00000000;

    // Port D initialization
    // PD7, PD6, PD5, PD4, PD3, PD2, PD1, PD0
    DDRD = 0b00000000;
    PORTD = 0b00000000;
}

// Timer/Counter 2 initialization
void Timer2_Init( void )
{
    TCNT2 = 45;

    // COM2A1 COM2A0 COM2B1 COM2B0 - - WGM21 WGM20
    TCCR2A = 0;

    // FOC2A FOC2B - - WGM22 CS22 CS21 CS20
    TCCR2B = 0;

    // - - - - - OCIE2B OCIE2A TOIE2
    TIMSK2 = (1<<TOIE2);

    // - - - - - OCF2B OCF2A TOV2
    TIFR2 = (1<<TOV2);
}

void setup()
{
    // Global disable interrupts
    cli();

    // Input/Output Ports initialization
    Ports_Init();

    // Timer/Counter 2 initialization
    Timer2_Init();

    // Global enable interrupts
    sei();
}

void loop()
{
    if ( (PINC & 0b00001111) == 0b00001110 )
        IR_send(CODE1);

    if ( (PINC & 0b00001111) == 0b00001101 )
        IR_send(CODE2);

    if ( (PINC & 0b00001111) == 0b00001011 )
        IR_send(CODE3);

    if ( (PINC & 0b00001111) == 0b00000111 )
        IR_send(CODE4);

    if ( (PINC & 0b00001111) == 0b00000110 )
        IR_send(CODE5);

    if ( (PINC & 0b00001111) == 0b00001001 )
        IR_send(CODE6);
}

ISR(TIMER2_OVF_vect)
{
    TCNT2 += 45;

    if ( count < 20 )
        PORTB ^= 1;

    count += 1;
}

//
// End
//
////////////////////////

В этом проекте используется протокол ИК связи аналогичный описанному в http://justforduino.blogspot.ru/2014/01/blog-post.html

Получилась простая и недорогая дистанционно управляемая платформа. Правда есть у неё и недостатки. Они свойственны ИК связи вообще. Дело в том, что такая связь работает в пределах одной комнаты. Стены непроницаемы для инфракрасного света. А на улице расстояние связи сокращается весьма существенно. Особенно в ясный солнечный день.